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 `<main>'

~~~

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: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>