It seems like having multiple dispatch on keyword arguments would expand the power of the language and would also have the benefit of consistency in behavior. Much like the original poster, I also expected multiple dispatch to work on keyword arguments based on my experience with positional arguments. I am interested in understanding the difficulty of using multiple dispatch on keyword arguments. Here are some of my thoughts:
At least from my naive point of view as a user, it seems like positional arguments would work as usual, keyword arguments would match name and type, and the optional kwargs could work similar to varargs where types could be declared optionally. Consider the following example,
function foo(a,b;c::Int64,d::Int64,kwargs...)
#...
end
function foo(a,b;c::Float64,d::Float64,kwargs...)
#...
end
function foo(a,b;c::Float64,d::Float64,e::Int64,kwargs...)
#...
end
Each function is distinguished by the keyword types. As far as I can tell, the most important constraints are imposing unique argument names and distinguishable types in order to avoid method ambiguity, which does not introduce a new rule. In the example above, foo(1,2;c=.3,d=.2,e=.3)
would call the second version of foo because it is not an Int64. However, foo(1,2;c=.3,d=.2,e=3)
would call the third version of foo because it is an Int64. The rule in the later case is to call the most specific matching method. For a lack of better word, let’s call this the rule of specificity, which seems to already be in place, e.g. myfun(a::Int64,b::Int64
) and myfun(a,b)
are not ambiguous.
One possible conflict may arise when kwargs… is contained by a type. For example, replace the second version of foo above with the following:
function foo(a,b;c::Float64,d::Float64,kwargs::Int64...)
#...
end
Let’s call this 2’. Which method should be called when given: foo(1,2;c=.3,d=.2,e=3)
? In this case, 2’ and 3 both match in terms of type and name because e=3 could be in kwargs..
. So one solution might be to prohibit type declarations on kwargs...
. However, I don’t think that is necessary. In keeping with the rule of specificity, dispatch on version 3 because the keyword e::Int64
is explicitly declared in the method definition, making it more specific than 2’.
That seems straightforward to me as a user, especially with concrete examples illustrating how the rules work. Considering that language developers struggled with this, I suspect I am missing something important. Is there an edge case that I failed to consider? Is there a large cost in parsing unordered keyword arguments and enforcing these rules? I would be interested in understanding more about this.