The Crystal Programming Language Forum

Named arguments usage ambiguity

Is this a bug or I am doing something wrong? Compiler doesn’t show any error if named argument to a function passed using = or :. But if I use = then it considers as positional argument.

def hello(message, first_name="", last_name="")
	puts "Message=#{message}  First Name=#{first_name}  Last Name=#{last_name}"
end
 
hello("Hello")
hello("Hello", "Aravinda", "VK")
hello("Hello", first_name: "Aravinda", last_name: "VK")
hello("Hello", first_name="Aravinda", last_name="VK")
 
hello("Hello", last_name="All")
hello("Hello", last_name: "All")

Output:

Message=Hello  First Name=  Last Name=
Message=Hello  First Name=Aravinda  Last Name=VK
Message=Hello  First Name=Aravinda  Last Name=VK
Message=Hello  First Name=Aravinda  Last Name=VK
Message=Hello  First Name=All  Last Name=
Message=Hello  First Name=  Last Name=All

first_name="Aravinda" is an assignment to a local variable and the value of that expression is the assigned value.
hello(first_name="Aravinda") is semantically equivalent to first_name="Aravinda"; hello(first_name). You see, it is a positional argument.

Named arguments need to be specified with : after the argument name.

2 Likes

Thanks. Now it makes sense.

I am wondering if the compiler should not complain that an assignment in a method call is invalid. I still frequently do the error (switching between python and crystal does not help) and it is not always easy to see.

Anyway I think ameba catches it :heart: .

2 Likes

I always said that assignment should be required to have parentheses around it, if it’s not top-level. Python has this requirement. And in Crystal I voluntarily always write it as such.

So this would be disallowed syntax:

hello("Hello", first_name="Aravinda", last_name="VK")

But if you really wanted assignment, you could write:

hello("Hello", (first_name = "Aravinda"), (last_name = "VK"))

Of course this is all moot now, and indeed only external analyzers will be able to save you. Compiler warnings aren’t a thing, and I don’t think a breaking change of any sort would fly here.

I suppose one of the problems is that assignment arguments are natural for macro calls like property first_name = "Aravinda", but macro and method calls are identical on a syntax level. That would move the decision about being valid to the semantic stage. That’s still doable, but not as straightforward as one might expect.
Overall, I don’t think the compiler needs to apply artificial restrictions. This looks lika a really good use case for a linter.

1 Like