Re @govorunov, I would honestly find the semantics you suggest very confusing and error-prone. Specifically, having two methods with exactly the same type signature would be strage, especially considering that in Julia, typically, the order in which methods of a function are defined is irrelevant, it has no effect on the runtime behavior.
In case of your example:
foo(a, b::Int=1)="Method 1"
foo(a, K:Int)="Method 4"
foo(a; K)="Method 5"
# Why Method 5, why not Method 1? What's the purpose of the default value for b in Method 1?
foo(1) # Method 5 as before
# Method 1 or Mathod 4? Why?
foo(1, 1) ?
Furthermore, this would be also very-very confusing:
foo(5, K=5) # Method 5
foo(5, K=5;) # Method 4
Not to mention that it would be a breaking change. In Julia, having a semicolon at the end of the parameter list doesn’t change anything. There are no keyword arguments? Fine.
Your suggestions also ignore the intricate behavior of splatting regular and keyword arguments. What would the following calls do?
kwargs = (K = 5,)
f(1, kwargs...)
f(1; kwargs...)
f(1, kwargs...;)
kwargs = (;)
f(1, kwargs...)
f(1; kwargs...)
f(1, kwargs...;)
In Julia, these are all clearly defined, and quite easy to remember. Your recommended modifications would bring a ton of complexity into the system.
If you wan’t to handle various combinations of named parameters in your methods, I suggest you introduce auxiliary structures. E.g.,
Base.@kwdef struct F1
b::Int = 1
end
Base.@kwdef struct F2
b::Float64 = 1.0
end
Base.@kwdef struct F3
D::String
end
Base.@kwdef struct F4
K::Int
end
f(a, args::F1) = "Method 1"
f(a, args::F2) = "Method 2"
f(a, args::F3) = "Method 3"
f(a, args::F4) = "Method 4"
f(a; K = nothing) = "Method 5"
f(5, F1(b = 3)) # Method 1
f(1, F2(1.0)) # Method 2
f(5, F3("test")) # Method 3
f(5, F4(K = 5)) # Method 4
f(1) # Method 5
f("test") # Method 5
f(5, K = 5) # Method 5
f(5; K = 5) # Method 5
Of course, in the specific implementation, the structs would have more semantic, meaningful names.
Alternatively you can use empty tag structs to select the approriate method:
struct T1 end
struct T2 end
f(::Type{T1}, a, b::Int = 1) = ...
f(::Type{T2}, a, D::String) = ...
f(T1, 1)
f(T2, "foo")
And I’m sure there are many more ways to achieve what you are aiming for in a very Juliaesque way.