Define f with keyword arguments: function f does not accept keyword arguments

Hi,
I thought this may have be a documentation issue, but now I think I have misunderstood.
I’m following the optional and keyword arguments in the docs.
I was surprised by the following:

julia> f(a=1,b=2)=1+2b
f (generic function with 3 methods) 
julia> f(b=1,a=2)
ERROR: function f does not accept keyword arguments

It seems that I mistook the example to be referring to optional and keyword arguments, when it is only an example of optional arguments - that is fine.
However, the error message implanted in my mind that this is definitely (unambiguously) not a function that accepts keywords.

After some digging I realized I had thought I was looking at something like this definition (update: please see the comment below):

julia> f(; a=1,b=2)=2a+4b
f (generic function with 3 methods) # **See the update below**
julia> f(b=1,a=2)
8

Now, in the following, I expected to get a ambiguity error instead of 10

julia> f()
10

On reflection I suppose I was “expecting” one of two things:

  1. the definition f(a=1,b=2)=a+2b to throw an error about a missing ;, or for f(b=1,a=2) to return 4
  2. 6 4 defintions of f: 3 using positional arguments, and 3 1 using keyword arguments and f() to throw an ambiguity error.

Obviously I’ve got something horribly wrong. Appreciate any help.

1 Like

That seems pretty bad, it is very useful to be able to define default values of arguments.

f() is overwritten by the keyword definition. Why would there be 3 methods for the keyword arguments?

1 Like

I think this sould give you a hint:

From my understanding, f(a=1,b=2)=1+2b actually creates 3 methods, one without arguments, one just with one argument a and one with both arguments. Keywords don’t participate in dispatch at all, so f(;a=0, b=1) = ... just overrides your definition for no parameters and is the one getting called by f()

1 Like

No argument here. So that section is only about default/optional arguments and not about keyword arguments?

Honestly I’m in the dark here, but given that in one definition f(b=1,a=2) throws and error and for the other it returns a value, it seemed to me that Julia recognizes f(a=1,b=2)=... is distinct from f(;a=1,b=2)=.... So I (obviously wrongly) thought maybe the same applied to the 3 definitions. Again I’m not arguing any of my understanding makes sense - I am confused.

It appears the explanation is: that documentation section deals with (positional) default values not keyword values, hence the ERROR: function f does not accept keyword arguments is expected?

The last part is the thing about keyword arguments:

Keyword arguments behave quite differently from ordinary positional arguments. In particular, they do not participate in method dispatch. Methods are dispatched based only on positional arguments, with keyword arguments processed after the matching method is identified.

1 Like

@taqtiqa-mark Thanks for putting the question out there. I ran into something like this recently and gave up and simplified what I was doing but now realize that I got confused in a similar fashion to how you did. I think in my case I have some implicitly pythonic assumptions about how things should work that trip me up.

1 Like

Yes, the overriding confused me… the initial error from f(b=1, a=2) and then its success made me think that Julia could distinguish the two methods.

On reflection… maybe f(b=1, a=2) should still throw an error and f(;b=1, a=2) should return 8?

Ack.

That wouldn’t make sense to me. f(b=1, a=2) is a very useful shortcut to save having to create three different method definitions and should not be confused as keyword arguments. Keyword arguments are always optional and can only be specified by name. You also can’t do dispatch on them based on types. f(;b=1, a=2) therefore represents quite a different use case, and you should decide depending on your use case, what the most intuitive way of calling your function with these arguments is.

Agreed, except the shortcut methods defining default values was actually defined for the non-keyword method f(a=2,b=1), and now f(b=1,a=2) quietly succeeds (instead of throwing an error) simply because elsewhere I defined a method that, by coincidence (misfortune in production), happens to use the same names for keywords.

Without defining the keyword method f(a=2, b=1) would have failed as well.

2 Likes

:bulb: That did it. :blush:

Update:
The following was an artifact of using the same REPL session used to define f(a=1,b=2):

In fact in v1.0.2 using a clean REPL:

julia> f(;a=1,b=2)=2a+4b
f (generic function with 1 method)

julia> f(b=1,a=2)
8

julia> f()
10

For those following along at home…

@klaff and I were not alone….
Some attempt at documenting what the current behavior is…