[ruby-core:117992] [Ruby master Bug#20505] Reassigning the block argument in method body keeps old block when calling super with implicit arguments

Issue #20505 has been reported by Earlopain (A S). ---------------------------------------- Bug #20505: Reassigning the block argument in method body keeps old block when calling super with implicit arguments https://bugs.ruby-lang.org/issues/20505 * Author: Earlopain (A S) * Status: Open * ruby -v: 3.3.1 * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- You can call super without arguments and parenthesis to pass along all the enclosing method arguments to the parent method. You can modify positional and keyword arguments before the call to super, and the parent method will recieve these modified values. With the block arg however that isn't the case: ```rb class A def positional_arg(a) puts a end def block_arg(&block) yield end end class B < A def positional_arg(a = nil) a = 'b' super end def block_arg(&block) block = proc { puts 'b' } super end end B.new.positional_arg('a') B.new.positional_arg B.new.block_arg { puts 'a' } B.new.block_arg ``` I would expect this snippet to print `b` four times. The actual output is `b` `b` `a` and `LocalJumpError`. To get the desired output I must pass the block along explicitly with `super(&block)`. I hope my example explains the issue good enough. I have looked through issues here and searched for documentation and haven't found any mention of this behaviour. Sorry if I missed something somewhere. -- https://bugs.ruby-lang.org/

Issue #20505 has been updated by nobu (Nobuyoshi Nakada). I think that's what it is. `Proc` is an instantiated block representation, but not a block itself. ---------------------------------------- Bug #20505: Reassigning the block argument in method body keeps old block when calling super with implicit arguments https://bugs.ruby-lang.org/issues/20505#change-108415 * Author: Earlopain (A S) * Status: Open * ruby -v: 3.3.1 * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- You can call super without arguments and parenthesis to pass along all the enclosing method arguments to the parent method. You can modify positional and keyword arguments before the call to super, and the parent method will recieve these modified values. With the block arg however that isn't the case: ```rb class A def positional_arg(a) puts a end def block_arg(&block) yield end end class B < A def positional_arg(a = nil) a = 'b' super end def block_arg(&block) block = proc { puts 'b' } super end end B.new.positional_arg('a') B.new.positional_arg B.new.block_arg { puts 'a' } B.new.block_arg ``` I would expect this snippet to print `b` four times. The actual output is `b` `b` `a` and `LocalJumpError`. To get the desired output I must pass the block along explicitly with `super(&block)`. I hope my example explains the issue good enough. I have looked through issues here and searched for documentation and haven't found any mention of this behaviour. Sorry if I missed something somewhere. -- https://bugs.ruby-lang.org/

Issue #20505 has been updated by Earlopain (A S). nobu (Nobuyoshi Nakada) wrote in #note-1:
I think that's what it is. `Proc` is an instantiated block representation, but not a block itself.
Ok, I see what you mean. This makes sense, somewhat. You could also just assign a string literal which makes even less sense, didn't think about that beforehand You do have two values hiding behind the same name which is pretty confusing. I would expect super to take the modified argument and raise when it is not blocklike, or perhaps raise earlier on assign when not blocklike. ---------------------------------------- Bug #20505: Reassigning the block argument in method body keeps old block when calling super with implicit arguments https://bugs.ruby-lang.org/issues/20505#change-108416 * Author: Earlopain (A S) * Status: Open * ruby -v: 3.3.1 * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- You can call super without arguments and parenthesis to pass along all the enclosing method arguments to the parent method. You can modify positional and keyword arguments before the call to super, and the parent method will recieve these modified values. With the block arg however that isn't the case: ```rb class A def positional_arg(a) puts a end def block_arg(&block) yield end end class B < A def positional_arg(a = nil) a = 'b' super end def block_arg(&block) block = proc { puts 'b' } super end end B.new.positional_arg('a') B.new.positional_arg B.new.block_arg { puts 'a' } B.new.block_arg ``` I would expect this snippet to print `b` four times. The actual output is `b` `b` `a` and `LocalJumpError`. To get the desired output I must pass the block along explicitly with `super(&block)`. I hope my example explains the issue good enough. I have looked through issues here and searched for documentation and haven't found any mention of this behaviour. Sorry if I missed something somewhere. -- https://bugs.ruby-lang.org/

Issue #20505 has been updated by mame (Yusuke Endoh). Actually, `super` is totally confusing. Do you know that `super()` passes the block argument? I have been using Ruby for 20 years and never knew about it until recently. ``` class A def foo yield end end class B < A def foo super() # delegates the given block! end end B.new.foo { puts "Hello" } #=> Hello ``` As for `super`, I don't think it is a good idea to change the behavior based on only partial consistency. My personal preference is to deprecate no-argument `super`, if possible. We have `super(...)` now, which looks much better to me. ---------------------------------------- Bug #20505: Reassigning the block argument in method body keeps old block when calling super with implicit arguments https://bugs.ruby-lang.org/issues/20505#change-108417 * Author: Earlopain (A S) * Status: Open * ruby -v: 3.3.1 * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- You can call super without arguments and parenthesis to pass along all the enclosing method arguments to the parent method. You can modify positional and keyword arguments before the call to super, and the parent method will recieve these modified values. With the block arg however that isn't the case: ```rb class A def positional_arg(a) puts a end def block_arg(&block) yield end end class B < A def positional_arg(a = nil) a = 'b' super end def block_arg(&block) block = proc { puts 'b' } super end end B.new.positional_arg('a') B.new.positional_arg B.new.block_arg { puts 'a' } B.new.block_arg ``` I would expect this snippet to print `b` four times. The actual output is `b` `b` `a` and `LocalJumpError`. To get the desired output I must pass the block along explicitly with `super(&block)`. I hope my example explains the issue good enough. I have looked through issues here and searched for documentation and haven't found any mention of this behaviour. Sorry if I missed something somewhere. -- https://bugs.ruby-lang.org/

Issue #20505 has been updated by Earlopain (A S). mame (Yusuke Endoh) wrote in #note-3:
Actually, `super` is totally confusing. Do you know that `super()` passes the block argument? I have been using Ruby for 20 years and never knew about it until recently.
``` class A def foo yield end end
class B < A def foo super() # delegates the given block! end end
B.new.foo { puts "Hello" } #=> Hello ```
As for `super`, I don't think it is a good idea to change the behavior based on only partial consistency.
My personal preference is to deprecate no-argument `super`, if possible. We have `super(...)` now, which looks much better to me.
I believe super always passes the block along, unless you explitly do `&nil`. I guess it works out most of the time but it is one of the things I wish Ruby didn't do. But changing that would be hugely disruptive I think. This goes along with all methods accepting a block without declaring they do so, and in that context always passing it along does make sense since the method may not even have a block arg to exicitly pass along. ---------------------------------------- Bug #20505: Reassigning the block argument in method body keeps old block when calling super with implicit arguments https://bugs.ruby-lang.org/issues/20505#change-108418 * Author: Earlopain (A S) * Status: Open * ruby -v: 3.3.1 * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- You can call super without arguments and parenthesis to pass along all the enclosing method arguments to the parent method. You can modify positional and keyword arguments before the call to super, and the parent method will recieve these modified values. With the block arg however that isn't the case: ```rb class A def positional_arg(a) puts a end def block_arg(&block) yield end end class B < A def positional_arg(a = nil) a = 'b' super end def block_arg(&block) block = proc { puts 'b' } super end end B.new.positional_arg('a') B.new.positional_arg B.new.block_arg { puts 'a' } B.new.block_arg ``` I would expect this snippet to print `b` four times. The actual output is `b` `b` `a` and `LocalJumpError`. To get the desired output I must pass the block along explicitly with `super(&block)`. I hope my example explains the issue good enough. I have looked through issues here and searched for documentation and haven't found any mention of this behaviour. Sorry if I missed something somewhere. -- https://bugs.ruby-lang.org/

Issue #20505 has been updated by jeremyevans0 (Jeremy Evans). Status changed from Open to Rejected This was discussed in yesterday's dev meeting, and the decision was made to keep the current behavior: https://github.com/ruby/dev-meeting-log/blob/master/2024/DevMeeting-2024-07-... ---------------------------------------- Bug #20505: Reassigning the block argument in method body keeps old block when calling super with implicit arguments https://bugs.ruby-lang.org/issues/20505#change-109087 * Author: Earlopain (A S) * Status: Rejected * ruby -v: 3.3.1 * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- You can call super without arguments and parenthesis to pass along all the enclosing method arguments to the parent method. You can modify positional and keyword arguments before the call to super, and the parent method will recieve these modified values. With the block arg however that isn't the case: ```rb class A def positional_arg(a) puts a end def block_arg(&block) yield end end class B < A def positional_arg(a = nil) a = 'b' super end def block_arg(&block) block = proc { puts 'b' } super end end B.new.positional_arg('a') B.new.positional_arg B.new.block_arg { puts 'a' } B.new.block_arg ``` I would expect this snippet to print `b` four times. The actual output is `b` `b` `a` and `LocalJumpError`. To get the desired output I must pass the block along explicitly with `super(&block)`. I hope my example explains the issue good enough. I have looked through issues here and searched for documentation and haven't found any mention of this behaviour. Sorry if I missed something somewhere. -- https://bugs.ruby-lang.org/

Issue #20505 has been updated by matz (Yukihiro Matsumoto). Keep the assignment to the block argument as it is; If we want to discuss `super`'s behavior, let's discuss it in another issue. Matz. ---------------------------------------- Bug #20505: Reassigning the block argument in method body keeps old block when calling super with implicit arguments https://bugs.ruby-lang.org/issues/20505#change-109132 * Author: Earlopain (A S) * Status: Rejected * ruby -v: 3.3.1 * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- You can call super without arguments and parenthesis to pass along all the enclosing method arguments to the parent method. You can modify positional and keyword arguments before the call to super, and the parent method will recieve these modified values. With the block arg however that isn't the case: ```rb class A def positional_arg(a) puts a end def block_arg(&block) yield end end class B < A def positional_arg(a = nil) a = 'b' super end def block_arg(&block) block = proc { puts 'b' } super end end B.new.positional_arg('a') B.new.positional_arg B.new.block_arg { puts 'a' } B.new.block_arg ``` I would expect this snippet to print `b` four times. The actual output is `b` `b` `a` and `LocalJumpError`. To get the desired output I must pass the block along explicitly with `super(&block)`. I hope my example explains the issue good enough. I have looked through issues here and searched for documentation and haven't found any mention of this behaviour. Sorry if I missed something somewhere. -- https://bugs.ruby-lang.org/
participants (5)
-
Earlopain (A S)
-
jeremyevans0 (Jeremy Evans)
-
mame (Yusuke Endoh)
-
matz (Yukihiro Matsumoto)
-
nobu (Nobuyoshi Nakada)