Overloaded method missing


#1

Hi, I have tried to imnplement 2 methods those have same name and different optional named arguments pattern.

But, I couldn’t call those methods other than last defined.
Those will rise compile time error when called.

Minimal code is as follows:

def foo(*, s : String? = nil)
  p s
end

def foo(*, c : Char? = nil)
  p c
end

foo(s: "S")
# Error in test/test.cr:9: no argument named 's' (did you mean 'c'?)
# Matches are:
#  - foo(*, c : Char | ::Nil = nil)
# 
# foo(s: "S")
# ^~~

Any problems in above code?


#2

The problem is the both methods have a default value of nil. What happens if you call foo without arguments at all? Both overloads match. That’s why the compiler say “okay, if they are both the same in that way, the second one stays, I’ll discard the first one”. Or at least that’s how the compiler works (both arguments have a default value so they are equally stronger and the last one wins).

To fix this you will need to remove the default values. If you need to also invoke foo without any argument you can provide a third overload.

def foo(*, s : String?)
  p s
end

def foo(*, c : Char?)
  p c
end

def foo
  p "empty"
end

foo(s: "S")
foo(c: 'c')
foo

Proof: https://play.crystal-lang.org/#/r/67jb


#3

That said, the compiler could probably keep all overloads and then try to match them all in order if there’s an explicit argument. So you could create a bug/issue for this (though at least I won’t fix it soon).


#4

I understood why it happen.

Indeed it’s not a good situation that one method call matches multiple definitions.

I will try to devise method definitions in my code.

Thank you.