Project

General

Profile

Actions

Feature #16378

closed

Support leading arguments together with ...

Added by Eregon (Benoit Daloze) about 5 years ago. Updated 4 months ago.

Status:
Closed
Target version:
[ruby-core:95993]

Description

I think this is very important, otherwise ... can be used only very rarely.

For instance, method_missing typically want to access the method name like:

def method_missing(name, ...)
  if name.to_s.end_with?('?')
    self[name]
  else
    fallback(name, ...)
  end
end

See the original feature: https://bugs.ruby-lang.org/issues/16253#note-19.
I think most people expect def method_missing(name, ...) to work.


Files

ruby_2_7_lead_args_forwarding.patch (8.98 KB) ruby_2_7_lead_args_forwarding.patch jeremyevans0 (Jeremy Evans), 06/19/2020 04:20 PM

Related issues 3 (0 open3 closed)

Related to Ruby master - Feature #16253: Shorthand "forward everything" syntaxClosedActions
Related to Ruby master - Feature #16891: Restore Positional Argument to Keyword ConversionRejectedmatz (Yukihiro Matsumoto)Actions
Related to Ruby master - Feature #16463: Fixing *args-delegation in Ruby 2.7: ruby2_keywords semantics by default in 2.7.1Closedmatz (Yukihiro Matsumoto)Actions
Actions #1

Updated by Eregon (Benoit Daloze) about 5 years ago

  • Related to Feature #16253: Shorthand "forward everything" syntax added
Actions #2

Updated by Eregon (Benoit Daloze) about 5 years ago

  • Description updated (diff)
  • Target version set to 2.7

Updated by Eregon (Benoit Daloze) about 5 years ago

Also I believe ... could be a good way to do delegation in all versions for lexical cases (the majority):

# Could be some constant in a gem
ARGS = RUBY_VERSION < "2.7" ? "*args, &block" : "..."

class_eval <<RUBY
def method_missing(name, #{ARGS})
  if name.to_s.end_with?('?')
    self[name]
  else
    fallback(name, #{ARGS})
  end
end
RUBY

And while Redmine doesn't syntax highlight <<RUBY, at least GitHub and RubyMine do.

Updated by matz (Yukihiro Matsumoto) about 5 years ago

  • Status changed from Open to Rejected

I know trailing ... can be very useful from C experience. But the primary purpose of Ruby ... is method delegation. We are not going to extend the role of ... in the language (at least for now).

Matz.

Updated by Eregon (Benoit Daloze) about 5 years ago

matz (Yukihiro Matsumoto) wrote:

I know trailing ... can be very useful from C experience. But the primary purpose of Ruby ... is method delegation. We are not going to extend the role of ... in the language (at least for now).

That is surprising.
It makes ... unusable in many delegation use cases which need to extract the first(s) arguments.
The above method_missing is also delegation, isn't it?

What's your solution for that case?
Using ruby2_keywords def method_missing(name, *args) and then having to change it to def method_missing(name, *args, **kwargs) once ruby2_keywords is removed?
Defining method_missing is not something rare in Ruby. It seems a shame ... can't be used there, even though it would a very good place to use ... (delegation in method_missing is almost always lexical).

BTW, R has ... and it supports leading arguments.
And of course the construct that ... replaces, that is *args, &block as "all arguments" supports leading arguments too.

Updated by Eregon (Benoit Daloze) almost 5 years ago

  • Status changed from Rejected to Open
  • Assignee set to matz (Yukihiro Matsumoto)
  • Target version changed from 2.7 to 3.0

@matz (Yukihiro Matsumoto) Could you reply to this?

Particularly:

But the primary purpose of Ruby ... is method delegation.

Indeed, and I believe we also want to extract leading arguments in many delegation use cases.
... not supporting leading arguments is a obvious limitation and I would think unexpected for many rubyists.
As an example, it makes ... unusable for method_missing, which is a place where delegation often happens.

I think the decision was too quick, maybe because I set target version 2.7.
It won't be in 2.7 since that's released, but let's consider it for future releases.

Updated by Dan0042 (Daniel DeLorme) almost 5 years ago

In the DevelopersMeeting20191017Japan log there was "Future work: lead argument handling is postponed", so clearly there was the intention of adding it later.

Updated by matz (Yukihiro Matsumoto) almost 5 years ago

We have found out that #method_missing (and #send) needed leading arguments otherwise we cannot use argument forwarding for them. I changed my mind. Accepted.

Matz.

Actions #9

Updated by Eregon (Benoit Daloze) over 4 years ago

  • Related to Feature #16891: Restore Positional Argument to Keyword Conversion added

Updated by Eregon (Benoit Daloze) over 4 years ago

Interesting, I never saw the reply above from matz.
Looking at my email I received one but it wasn't attached to the rest of the conversation for this issue for some reason.

Great to hear it's now accepted.

I think we should have it already in 2.7.2+.
Many people clearly want it in #16891.

@jeremyevans0 (Jeremy Evans) or @nobu (Nobuyoshi Nakada) Could you implement it on master?

Actions #11

Updated by Eregon (Benoit Daloze) over 4 years ago

  • Related to Feature #16463: Fixing *args-delegation in Ruby 2.7: ruby2_keywords semantics by default in 2.7.1 added

Updated by jeremyevans0 (Jeremy Evans) over 4 years ago

Eregon (Benoit Daloze) wrote in #note-10:

@jeremyevans0 (Jeremy Evans) or @nobu (Nobuyoshi Nakada) Could you implement it on master?

I've implemented basic support, which passes make check: https://github.com/jeremyevans/ruby/commit/672901facca6f88ae40b4ea8ef59ef04efd5a5de

I think ripper support is probably broken for it, and the idFWD_KWREST sections (not currently enabled) are probably also wrong.

@nobu (Nobuyoshi Nakada), could you please fix the ripper support and idFWD_KWREST sections?

Updated by jeremyevans0 (Jeremy Evans) over 4 years ago

jeremyevans0 (Jeremy Evans) wrote in #note-12:

Eregon (Benoit Daloze) wrote in #note-10:

@jeremyevans0 (Jeremy Evans) or @nobu (Nobuyoshi Nakada) Could you implement it on master?

I've implemented basic support, which passes make check: https://github.com/jeremyevans/ruby/commit/672901facca6f88ae40b4ea8ef59ef04efd5a5de

I think ripper support is probably broken for it, and the idFWD_KWREST sections (not currently enabled) are probably also wrong.

@nobu (Nobuyoshi Nakada), could you please fix the ripper support and idFWD_KWREST sections?

From my testing, the existing idFWD_KWREST sections for ... without leading arguments are already broken. Defining RUBY3_KEYWORDS in parse.y results in broken code such as args being dropped and no implicit conversion of nil into Hash (TypeError) when using super. So I don't think there is a point trying to get idFWD_KWREST sections working for leading arguments currently. We are not going to want to switch to idFWD_KWREST sections until we drop ruby2_keywords support, as ruby2_keywords is significantly faster.

I updated the commit to add ripper support, and added a pull request for it: https://github.com/ruby/ruby/pull/3190

Actions #14

Updated by jeremyevans (Jeremy Evans) over 4 years ago

  • Status changed from Open to Closed

Applied in changeset git|f8b4340fa2c254cd093ebc3bc70d2d0c46ea9997.


Add leading arguments support to arguments forwarding

The idFWD_KWREST sections may be wrong. However, the existing
idFWD_KWREST sections for ... without leading arguments are already
broken.

Implements [Feature #16378]

Updated by mame (Yusuke Endoh) over 4 years ago

@nagachika (Tomoyuki Chikanaga) Can we backport this to 2.7.2? Strictly speaking, this is a new feature, but according to public consultation about Ruby 3.0 keyword change, this seems important to mitigate the pain of the change in 2.7. Matz also agreed with the backport.

@jeremyevans0 (Jeremy Evans) If nagachika-san agreed with the backport, can you create a patch for backport?

Updated by jeremyevans0 (Jeremy Evans) over 4 years ago

mame (Yusuke Endoh) wrote in #note-15:

@jeremyevans0 (Jeremy Evans) If nagachika-san agreed with the backport, can you create a patch for backport?

Backport patch attached, in case @nagachika (Tomoyuki Chikanaga) approves.

Updated by nagachika (Tomoyuki Chikanaga) over 4 years ago

Thank you for your notice and providing the patch. I will take a look into it.

Updated by Dan0042 (Daniel DeLorme) almost 4 years ago

@nagachika (Tomoyuki Chikanaga) I would really like to see this backported to 2.7 ... may I ask for the status?

Updated by Eregon (Benoit Daloze) almost 4 years ago

Agreed it should be in 2.7 (well, I've said since the beginning of this issue :D).

Right now, I consider ... non-existing because it's almost never usable due to the restrictions in 2.7.

Updated by nagachika (Tomoyuki Chikanaga) almost 4 years ago

Thank you for ping me. I backported f8b4340f into ruby_2_7 at 27fca66207f2c35f2f44f6a7cbbe6fd153546082.

Updated by esad (Esad Hajdarevic) 4 months ago

Is there a reason why this doesn't work with keyword arguments too?

For example:

def foo(bar:, ...)
   other(...)
end

results in syntax error

Updated by jeremyevans0 (Jeremy Evans) 4 months ago

esad (Esad Hajdarevic) wrote in #note-21:

Is there a reason why this doesn't work with keyword arguments too?

For example:

def foo(bar:, ...)
   other(...)
end

results in syntax error

Keyword arguments are not leading arguments. Trying to support what you want was not in scope. I think trying to support what you want would significantly increase the complexity, especially if you wanted to support def foo(arg, kwarg: , ...) as well.

You should use:

def foo(*, bar:, **, &)
  other(*, **, &)
end
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0