From: merch-redmine@... Date: 2016-10-24T21:03:35+00:00 Subject: [ruby-core:77754] [Ruby trunk Feature#12861] super in a block can be either lexically or dynamically scoped depending on how the block is invoked Issue #12861 has been updated by Jeremy Evans. Tracker changed from Bug to Feature Assignee set to Yukihiro Matsumoto bug hit wrote: > Jeremy Evans wrote: > > > > One could argue that super is currently always relative to the current, dynamic method > > Except it's not. > > ```ruby > class Class1 > def self.foo > 'Class1::foo' > end > end > > class Class2 < Class1 > > def self.store_block(&block) > @block = block > end > > def self.foo > store_block do > super > end > end > > def self.call_stored_block > @block.() > end > > end > > Class2.foo > Class2.call_stored_block # "Class1::foo" > ``` > > When the block with super is invoked by Class2.call_stored_block, foo is not the current dynamic method, it's not even on the stack, and yet super calls foo because it is lexically bound to it. That's the current typical behavior of super, i.e. lexical method binding. The one exception is when super is in a block/proc invoked as a method. When the block with super is invoked by Class2.call_stored_block, `foo` is the current method at that point, according to `__method__`. This is simple to see by changing Class1.foo to raise an exception in your example, using `__method__` from inside the block: ~~~ ruby class Class1 def self.foo(v) raise v end end class Class2 < Class1 def self.store_block(&block) @block = block end def self.foo store_block do super(__method__.to_s) end end def self.call_stored_block @block.() end end Class2.foo Class2.call_stored_block # super_test.rb:3:in `foo': foo (RuntimeError) # from super_test.rb:15:in `block in foo' # from super_test.rb:20:in `call_stored_block' # from super_test.rb:26:in `
' ~~~ Notice how the backtrace states "block in foo" (in ruby 1.8.7, it just shows "foo"), and you can see that `__method__` in the block is :foo, show by the exception message. It's already possible to get your desired behavior via super_method, changing ruby's behavior in regards to super will break a large amount of existing code, and the way super currently works in ruby makes sense (calling the super of the current `__method__`). This behavior dates back to at least ruby 1.8.7. This is a request for a language behavior change, not a request for a bug fix. I'm changing this from Bug to Feature, and assigning to matz to make the decision. ---------------------------------------- Feature #12861: super in a block can be either lexically or dynamically scoped depending on how the block is invoked https://bugs.ruby-lang.org/issues/12861#change-61057 * Author: bug hit * Status: Open * Priority: Normal * Assignee: Yukihiro Matsumoto ---------------------------------------- ```ruby class Class1 def self.foo 'foo' end def self.method1 'method1' end end class Class2 < Class1 def self.foo bar do super() end end def self.bar(&block) a = block.() define_singleton_method :method1, &block b = send(:method1) c = block.() [a, b, c] end end p Class2.foo # ["foo", "method1", "foo"] ``` It doesn't seem like a good idea for a given language construct to be either lexically or dynamically scoped, depending on how its surrounding block is invoked (which is not visible at the point of definition). I think it would be better if super were always lexically scoped, and a different keyword (dynamic_super) were always dynamically scoped -- https://bugs.ruby-lang.org/ Unsubscribe: