[ruby-core:111988] [Ruby master Feature#19370] Anonymous parameters for blocks?

Issue #19370 has been reported by zverok (Victor Shepelev). ---------------------------------------- Feature #19370: Anonymous parameters for blocks? https://bugs.ruby-lang.org/issues/19370 * Author: zverok (Victor Shepelev) * Status: Open * Priority: Normal ---------------------------------------- Just to clarify: are anonymous parameters delegation is planned to support in blocks? It would be a nice addition, if it is possible to implement: ```ruby # data in form [request method, URL, params]: [ [:get, 'https://google.com', {q: 'Ruby'}, {'User-Argent': 'Google-Chrome'}], [:post, 'https://gist.github.com', 'body'], # ... ].each { |method, *| request(method.to_s.upcase, *) } ``` ...and at the very least, consistent with what the method definition can have. If they are NOT planned to be implemented, I believe that at least error messages should be made much clearer, because currently, this would happen while running the code above:
no anonymous rest parameter (SyntaxError)
I understand the reason (the `request` clause doesn't "see" anonymous parameter of the **block**, and claims that current **method** doesn't have them), but it looks honestly confusing and inconsistent. -- https://bugs.ruby-lang.org/

Issue #19370 has been updated by nobu (Nobuyoshi Nakada). Status changed from Open to Assigned Assignee set to matz (Yukihiro Matsumoto) IIRC, matz was negative against it. ---------------------------------------- Feature #19370: Anonymous parameters for blocks? https://bugs.ruby-lang.org/issues/19370#change-101431 * Author: zverok (Victor Shepelev) * Status: Assigned * Priority: Normal * Assignee: matz (Yukihiro Matsumoto) ---------------------------------------- Just to clarify: are anonymous parameters delegation is planned to support in blocks? It would be a nice addition, if it is possible to implement: ```ruby # data in form [request method, URL, params]: [ [:get, 'https://google.com', {q: 'Ruby'}, {'User-Argent': 'Google-Chrome'}], [:post, 'https://gist.github.com', 'body'], # ... ].each { |method, *| request(method.to_s.upcase, *) } ``` ...and at the very least, consistent with what the method definition can have. If they are NOT planned to be implemented, I believe that at least error messages should be made much clearer, because currently, this would happen while running the code above:
no anonymous rest parameter (SyntaxError)
I understand the reason (the `request` clause doesn't "see" anonymous parameter of the **block**, and claims that current **method** doesn't have them), but it looks honestly confusing and inconsistent. -- https://bugs.ruby-lang.org/

Issue #19370 has been updated by zverok (Victor Shepelev). Note that it might lead to very confusing behavior when the surrounding method does have anonymous arguments: ```ruby def test(*) # ... proc { |*| p(*) }.call(1) end test(2) #=> prints 2 (method's anonymous arguments, not proc's) ``` Note that code is valid, and sanely looking syntax, which is very easy to (mis)interpret: it is "obvious" from the first sight that proc uses its anonymous args. The resulting behavior might be very confusing (especially in complicated code, long methods, and subtle differences in data). ---------------------------------------- Feature #19370: Anonymous parameters for blocks? https://bugs.ruby-lang.org/issues/19370#change-101559 * Author: zverok (Victor Shepelev) * Status: Assigned * Priority: Normal * Assignee: matz (Yukihiro Matsumoto) ---------------------------------------- Just to clarify: are anonymous parameters delegation is planned to support in blocks? It would be a nice addition, if it is possible to implement: ```ruby # data in form [request method, URL, params]: [ [:get, 'https://google.com', {q: 'Ruby'}, {'User-Argent': 'Google-Chrome'}], [:post, 'https://gist.github.com', 'body'], # ... ].each { |method, *| request(method.to_s.upcase, *) } ``` ...and at the very least, consistent with what the method definition can have. If they are NOT planned to be implemented, I believe that at least error messages should be made much clearer, because currently, this would happen while running the code above:
no anonymous rest parameter (SyntaxError)
I understand the reason (the `request` clause doesn't "see" anonymous parameter of the **block**, and claims that current **method** doesn't have them), but it looks honestly confusing and inconsistent. -- https://bugs.ruby-lang.org/

Issue #19370 has been updated by Dan0042 (Daniel DeLorme). zverok (Victor Shepelev) wrote:
If they are NOT planned to be implemented, I believe that at least error messages should be made much clearer, because currently, this would happen while running the code above:
no anonymous rest parameter (SyntaxError)
Perhaps this message would be clearer: "no anonymous rest parameter for method `xyz' (SyntaxError)" ---------------------------------------- Feature #19370: Anonymous parameters for blocks? https://bugs.ruby-lang.org/issues/19370#change-102671 * Author: zverok (Victor Shepelev) * Status: Assigned * Priority: Normal * Assignee: matz (Yukihiro Matsumoto) ---------------------------------------- Just to clarify: are anonymous parameters delegation is planned to support in blocks? It would be a nice addition, if it is possible to implement: ```ruby # data in form [request method, URL, params]: [ [:get, 'https://google.com', {q: 'Ruby'}, {'User-Argent': 'Google-Chrome'}], [:post, 'https://gist.github.com', 'body'], # ... ].each { |method, *| request(method.to_s.upcase, *) } ``` ...and at the very least, consistent with what the method definition can have. If they are NOT planned to be implemented, I believe that at least error messages should be made much clearer, because currently, this would happen while running the code above:
no anonymous rest parameter (SyntaxError)
I understand the reason (the `request` clause doesn't "see" anonymous parameter of the **block**, and claims that current **method** doesn't have them), but it looks honestly confusing and inconsistent. -- https://bugs.ruby-lang.org/

Issue #19370 has been updated by sawa (Tsuyoshi Sawada). zverok (Victor Shepelev) wrote in #note-2:
Note that it might lead to very confusing behavior when the surrounding method does have anonymous arguments:
```ruby def test(*) # ...
proc { |*| p(*) }.call(1) end ```
I think nesting anonymous arguments should be prohibited on as with numbered parameters: ```ruby "foo".then{_1.then{_1.upcase}} # >> SyntaxError ((irb):21: numbered parameter is already used in) outer block here ``` ---------------------------------------- Feature #19370: Anonymous parameters for blocks? https://bugs.ruby-lang.org/issues/19370#change-102676 * Author: zverok (Victor Shepelev) * Status: Assigned * Priority: Normal * Assignee: matz (Yukihiro Matsumoto) ---------------------------------------- Just to clarify: are anonymous parameters delegation is planned to support in blocks? It would be a nice addition, if it is possible to implement: ```ruby # data in form [request method, URL, params]: [ [:get, 'https://google.com', {q: 'Ruby'}, {'User-Argent': 'Google-Chrome'}], [:post, 'https://gist.github.com', 'body'], # ... ].each { |method, *| request(method.to_s.upcase, *) } ``` ...and at the very least, consistent with what the method definition can have. If they are NOT planned to be implemented, I believe that at least error messages should be made much clearer, because currently, this would happen while running the code above:
no anonymous rest parameter (SyntaxError)
I understand the reason (the `request` clause doesn't "see" anonymous parameter of the **block**, and claims that current **method** doesn't have them), but it looks honestly confusing and inconsistent. -- https://bugs.ruby-lang.org/

Issue #19370 has been updated by Dan0042 (Daniel DeLorme). sawa (Tsuyoshi Sawada) wrote in #note-4:
I think nested anonymous arguments should be prohibited as with numbered parameters:
That's a good idea, but does it mean this would become valid? ```ruby def test proc { |*| p(*) }.call(1) end ``` ---------------------------------------- Feature #19370: Anonymous parameters for blocks? https://bugs.ruby-lang.org/issues/19370#change-102687 * Author: zverok (Victor Shepelev) * Status: Assigned * Priority: Normal * Assignee: matz (Yukihiro Matsumoto) ---------------------------------------- Just to clarify: are anonymous parameters delegation is planned to support in blocks? It would be a nice addition, if it is possible to implement: ```ruby # data in form [request method, URL, params]: [ [:get, 'https://google.com', {q: 'Ruby'}, {'User-Argent': 'Google-Chrome'}], [:post, 'https://gist.github.com', 'body'], # ... ].each { |method, *| request(method.to_s.upcase, *) } ``` ...and at the very least, consistent with what the method definition can have. If they are NOT planned to be implemented, I believe that at least error messages should be made much clearer, because currently, this would happen while running the code above:
no anonymous rest parameter (SyntaxError)
I understand the reason (the `request` clause doesn't "see" anonymous parameter of the **block**, and claims that current **method** doesn't have them), but it looks honestly confusing and inconsistent. -- https://bugs.ruby-lang.org/

Issue #19370 has been updated by zverok (Victor Shepelev). After considering some examples, I believe it would be more consistent to just allow anonymous parameters in blocks, without further restrictions. The example of "confusing" example above: ```ruby def test(*) # ... proc { |*| p(*) }.call(1) # which * is that? end ``` ...can be rewritten with named arguments as well: ```ruby def test(x) # ... proc { |x| p(x) }.call(1) # which x is that? end ``` In any case, the current behavior is the most confusing, as demonstrated by #19983 ---------------------------------------- Feature #19370: Anonymous parameters for blocks? https://bugs.ruby-lang.org/issues/19370#change-105137 * Author: zverok (Victor Shepelev) * Status: Assigned * Priority: Normal * Assignee: matz (Yukihiro Matsumoto) ---------------------------------------- Just to clarify: are anonymous parameters delegation is planned to support in blocks? It would be a nice addition, if it is possible to implement: ```ruby # data in form [request method, URL, params]: [ [:get, 'https://google.com', {q: 'Ruby'}, {'User-Argent': 'Google-Chrome'}], [:post, 'https://gist.github.com', 'body'], # ... ].each { |method, *| request(method.to_s.upcase, *) } ``` ...and at the very least, consistent with what the method definition can have. If they are NOT planned to be implemented, I believe that at least error messages should be made much clearer, because currently, this would happen while running the code above:
no anonymous rest parameter (SyntaxError)
I understand the reason (the `request` clause doesn't "see" anonymous parameter of the **block**, and claims that current **method** doesn't have them), but it looks honestly confusing and inconsistent. -- https://bugs.ruby-lang.org/

Issue #19370 has been updated by mame (Yusuke Endoh). We discussed this issue and #19983 at the dev meeting. * Only method arguments can be delegated by `foo(*)`. * It should raise a SyntaxError to use `foo(*)` in a block that accepts `*` explicitly. * It is allowed to use `foo(*)` in a block that does not accept `*` explicitly. ```ruby def m(*) ->(*) { p(*) } # SyntaxError ->(x, *) { p(*) } # SyntaxError ->(x) { p(*) } #=> 1 proc {|x| p(*) } #=> 1 end m(1).call(2) ``` The main discussion was as follows. * `def m(*); ->(*) { p(*) }; end` is indeed confusing. * We want to prohibit a case where takes `*` and `**` from different blocks, such as `->(&) { ->(**) { ->(*) { foo(*, **, &) } }`. * We want to allow `def m(*) = @mutex.synchronize { m2(*) }` enclosed in a block that does not accept `*`. So we cannot prohibit to take arguments from outer blocks (or the method arguments). * Should we allow to take block arguments in unambiguous cases, such as `def m; ->(*) { p(*) }; end` ? * @knu: In many cases, what we want to delegate is the method arguments. * @ko1: Once we prohibit it, we can allow the delegation of block arguments later, if it is really needed. ---------------------------------------- Feature #19370: Anonymous parameters for blocks? https://bugs.ruby-lang.org/issues/19370#change-105217 * Author: zverok (Victor Shepelev) * Status: Assigned * Priority: Normal * Assignee: matz (Yukihiro Matsumoto) ---------------------------------------- Just to clarify: are anonymous parameters delegation is planned to support in blocks? It would be a nice addition, if it is possible to implement: ```ruby # data in form [request method, URL, params]: [ [:get, 'https://google.com', {q: 'Ruby'}, {'User-Argent': 'Google-Chrome'}], [:post, 'https://gist.github.com', 'body'], # ... ].each { |method, *| request(method.to_s.upcase, *) } ``` ...and at the very least, consistent with what the method definition can have. If they are NOT planned to be implemented, I believe that at least error messages should be made much clearer, because currently, this would happen while running the code above:
no anonymous rest parameter (SyntaxError)
I understand the reason (the `request` clause doesn't "see" anonymous parameter of the **block**, and claims that current **method** doesn't have them), but it looks honestly confusing and inconsistent. -- https://bugs.ruby-lang.org/

Issue #19370 has been updated by zverok (Victor Shepelev). To be completely honest, I think I have some counterarguments to the current conclusions. I believe the code that looks "logically possible" should be "physically possible" (unless there is a good argument why it is impossible, like the ambiguity of parsing). In the case of allowing forwarding in blocks, I find two questions below (with their answers) to be important. **Would this create new types of confusion?** I believe it **would not**. * `def m(*); ->(*) { p(*) };`, if it would **forward the proc args** MIGHT BE considered confusing. But it is confusing in EXACTLY the same way as `def m(a); ->(a) { p(a) };`; no new complication to explain here. Such cases with named variables are easily caught by the linter if the user wants (and doesn't stand in the way of quick experimenting). * but both current behavior (treating it as forwarding method's args) and proposed behaviors (prohibit some of the cases for the sake of disallowing potentially confusing code) would create **new types of confusion**. Procs/lambdas are Ruby's main functional construct, and the main intuition is that you can do with them what you can do with methods. Breaking this intuition creates learning impediments and falls into a mental bag of "weird language quirks you just need to remember." **Are there types of code where forwarding in procs/lambdas is necessary?** I believe **there are**. [One of the important drivers](https://bugs.ruby-lang.org/issues/16378) of `...` design was considering `method_missing`/`send`, i.e., metaprogramming. One of the main types of metaprogramming is `define_method`, which the author frequently wants to be short and expressive and allow to do everything that regular `def` does. The "start with `method_missing`, and then switch to `define_method` when the code matures" is one of the widespread approaches to designing various DSLs, and at that moment, the author is in a weird situation: ```ruby # code I had def method_missing(name, **) if ALLOWED_OPERATIONS.key?(name) ALLOWED_OPERATIONS[name].call(**) else super end end # code I want to replace it with: ALLOWED_OPERATIONS.each do |name, op| define_method(name) { |**| op.call(**) } end ``` ...but for some reason, I can not. I think it feels like a bug and nothing else. And for relatively new syntax features (which meet some pushback from the community anyway), such artificial limitations might lower the adoption: "Well, I tried it once, it never worked the way I wanted it to. Don't remember the exact reason, but it was confusing, so I don't use it anymore and recommend everyone to do the same." (Very infrequently such cases would be posted to the bug tracker/discussed in public for the core team to notice that there _was_ such need.) ---------------------------------------- Feature #19370: Anonymous parameters for blocks? https://bugs.ruby-lang.org/issues/19370#change-105409 * Author: zverok (Victor Shepelev) * Status: Assigned * Priority: Normal * Assignee: matz (Yukihiro Matsumoto) ---------------------------------------- Just to clarify: are anonymous parameters delegation is planned to support in blocks? It would be a nice addition, if it is possible to implement: ```ruby # data in form [request method, URL, params]: [ [:get, 'https://google.com', {q: 'Ruby'}, {'User-Argent': 'Google-Chrome'}], [:post, 'https://gist.github.com', 'body'], # ... ].each { |method, *| request(method.to_s.upcase, *) } ``` ...and at the very least, consistent with what the method definition can have. If they are NOT planned to be implemented, I believe that at least error messages should be made much clearer, because currently, this would happen while running the code above:
no anonymous rest parameter (SyntaxError)
I understand the reason (the `request` clause doesn't "see" anonymous parameter of the **block**, and claims that current **method** doesn't have them), but it looks honestly confusing and inconsistent. -- https://bugs.ruby-lang.org/

Issue #19370 has been updated by nobu (Nobuyoshi Nakada). https://github.com/ruby/ruby/pull/9330 ---------------------------------------- Feature #19370: Anonymous parameters for blocks? https://bugs.ruby-lang.org/issues/19370#change-105833 * Author: zverok (Victor Shepelev) * Status: Assigned * Priority: Normal * Assignee: matz (Yukihiro Matsumoto) ---------------------------------------- Just to clarify: are anonymous parameters delegation is planned to support in blocks? It would be a nice addition, if it is possible to implement: ```ruby # data in form [request method, URL, params]: [ [:get, 'https://google.com', {q: 'Ruby'}, {'User-Argent': 'Google-Chrome'}], [:post, 'https://gist.github.com', 'body'], # ... ].each { |method, *| request(method.to_s.upcase, *) } ``` ...and at the very least, consistent with what the method definition can have. If they are NOT planned to be implemented, I believe that at least error messages should be made much clearer, because currently, this would happen while running the code above:
no anonymous rest parameter (SyntaxError)
I understand the reason (the `request` clause doesn't "see" anonymous parameter of the **block**, and claims that current **method** doesn't have them), but it looks honestly confusing and inconsistent. -- https://bugs.ruby-lang.org/
participants (5)
-
Dan0042 (Daniel DeLorme)
-
mame (Yusuke Endoh)
-
nobu (Nobuyoshi Nakada)
-
sawa (Tsuyoshi Sawada)
-
zverok (Victor Shepelev)