Omitting named arguments values (Ruby 3.1 feature)

It should obviously be pointing to the left! :laughing:

x = 1
y = 2
call(x: <, y: <)
2 Likes
# Visual test:
Whatever(a_huge_name_of_something: <, another_crazy_stuff: <, a: 3)

Besides the known “less than” meaning, I think that it is contextually acceptable due to the lack of more proper options.

1 Like

To add a twist to this conversation, what if instead of saying
“infer the argument variable/method name from the keyword parameter name”
we said
“infer the keyword parameter name from the argument variable/method name”
?

this would change the “new syntax” to the first part, like:

some_method(_: var_name_as_param, _: blah_arg_as_param)
some_method(=: var_name_as_param, =: blah_arg_as_param)
some_method(:< var_name_as_param, :< blah_arg_as_param)
some_method(>: var_name_as_param, >: blah_arg_as_param)
some_method(:> var_name_as_param, :> blah_arg_as_param)
1 Like

To see if I get it, this would be an example of what you propose?

def foo(_ : String)
  p string  # <--- guessed name from the type of the parameter
end

For what it is worth, I used to be really skeptical about this feature in Ruby, but this April I started at a new job where they had decided to use implicit arguments wherever possible, and while it took a while to get used to it, I have actually learned to like it. I think I’d prefer that if it is stolen, then it is taken as is without any magic symbol. It is magic whatever is done, so it might as well be clean.

3 Likes

It probably means:

foo(one: 1, _: two, three; 3, _: four, _: five) # foo(one: 1, two: two, three: 3, four: four, five: five)

foo(_:x)   # allowed, formatter will insert a space after the `:`
foo(_ : x) # not allowed
foo(_: T)  # not allowed
foo(_ : T) # not allowed, not even as a `TypeDeclaration` node

build_fragment(io, _: indent, _: quote_char) do |xml|
  xml.start_document version, encoding
  yield xml
  # omit end_document because it is called in build_fragment
end

def self.from_filetime(filetime) : ::Time
  seconds, nanoseconds = filetime_to_seconds_and_nanoseconds(filetime)
  ::Time.utc(_: seconds, _: nanoseconds)
end

The _: inside a pair of {} indicates a named tuple:

{_: a, _: b}     # => {a: a, b: b}
{_=> a, _=> b}   # Error: can't read from _
{_ => a, _ => b} # Error: can't read from _

Def parameters are not affected, although whichever symbol we choose for this, there is always a chance a def parameter has the same external name:

def foo("_" a, b)
  {a, b}
end

b = 1
foo(_: b, "_": 2) # => {2, 1}

Personally I prefer *: because it bears some resemblance to * starting the list of named parameters in defs. This could be implemented as a pure parser transformation so that method dispatch and macros don’t have to deal with forwarded named arguments.

1 Like

Not read previous comment.

We are use this feature aggressively since our API project switch to ruby 3.1.

in fact, i enable it use rubocop, auto-correct every things, and auto change to it when save.

But, the fact is i don’t like it. following is reason:

  1. looks not good, you know, missing the balance.
  2. error prones, check my this issue and this

No. I think @HertzDevil got it right.
It has nothing to do with the type, only w/the parameter-name <-> argument-name matching.
Let me try again w/a simple example:

def parse(filename : String, counter : Int32)
  ... # some logic here
end

filename = "foo.bar"
counter = 100

# will match "filename" var used as argument with "filename" parameter and
# will match "counter" var used as argument with "counter" parameter
# inferring parameter names from argument names.
parse(_: filename, _: counter)

Summarizing:

  • inferring variable from argument name → looks bad for me, hides the argument variable used, seems magical.
  • inferring argument name from variable name → looks ok to me
3 Likes

I’d very much appreciate a feature like this being added to crystal. I don’t have strong opinions about the specific syntax, I can get comfortable learning whatever, as long as it was shorter to type than myvar: myvar multiple times :smile:

1 Like

@megatux has my vote. much better than the alternative.
I think that spelling out which variable you want to use in the method call is very important.
If the compiler can magically find the right param to assign it to (if I tell him with “_” or something else) is fine.

1 Like

From my perspective, the only options I see are not implementing this, or doing it exactly like in Ruby. People coming to Crystal from Ruby will know what that is. People coming from other languages will have to learn it. But if we go with another syntax, everyone will have to learn it, which is worse than “not everyone has to learn it”.

7 Likes

Is it? I don’t agree with that. If a new language does not do anything different (i.e. things to learn) than a precursor language, how could we ever get progress in software development.

Look at ruby and compare it to other languages at the time.
It is radicaly diffrent, with a lot of things people had to learn, whichever language they came from.

Having to learn a Language is not a bad thing.
It means that the creators of that language have innovated.
Created something new and hopefully better.

(sidenote: everytine I read of a new programming language and see basically a mix of C and python syntax with a years supply of all kinds of parenthesis, i despair and close the browser tab.)

3 Likes

I really do feel the same.

Although, i prefer not to add this feature, as i describe in my previous comment.