35

I have two classes A, and B. Class B overrides the foo method of class A. Class B has a bar method where I want to call the foo method of the super class. What is the syntax for such a call?

class A    
 def foo
   "hello"
 end    
end


class B < A
 def foo
  super + " world"
 end

 def bar
   # how to call the `foo` method of the super class?
   # something similar to
   super.foo
 end
end

For class methods I can call the methods up the inheritance chain by explicitly prefixing the class name. I wonder if there is a similar idiom for instance methods.

class P
 def self.x
   "x"
 end
end

class Q < P
 def self.x
   super + " x"
 end

 def self.y
   P.x
 end
end

Edit My use case is general. For a specific case I know I can use alias technique. This is a common feature in Java or C++, so I am curious to know if it is possible to do this without adding extra code.

Harish Shetty
  • 64,083
  • 21
  • 152
  • 198

5 Answers5

44

In Ruby 2.2, you can use Method#super_method now

For example:

class B < A
  def foo
    super + " world"
  end

  def bar
    method(:foo).super_method.call
  end
end

Ref: https://bugs.ruby-lang.org/issues/9781#change-48164 and https://www.ruby-forum.com/topic/5356938

zlx_star
  • 584
  • 5
  • 8
26

You can do:

 def bar
   self.class.superclass.instance_method(:foo).bind(self).call
 end
Sony Santos
  • 5,435
  • 30
  • 41
  • 25
    This cannot be the best way to call an overridden method in Ruby, please say it isn't so. Edit: yeah the comment in the question links to a better option. – Vinnyq12 May 30 '12 at 13:51
  • 3
    @Vinnyq12 Yes, `alias` is better for specific case, when you know the method you want to call from superclass; but here the OP is asking for a general case, without have to alias every method of superclass. – Sony Santos May 31 '12 at 00:28
14

In this particular case you can just alias :bar :foo before def foo in class B to rename the old foo to bar, but of course you can alias to any name you like and call it from that. This question has some alternative ways to do it further down the inheritance tree.

Community
  • 1
  • 1
Arkku
  • 41,011
  • 10
  • 62
  • 84
6

You can alias old_foo foo before redefining it to keep the old implementation around under a new name. (Technically it is possible to take a superclass's implementation and bind it to an instance of a subclass, but it's hacky, not at all idiomatic and probably pretty slow in most implementation to boot.)

Chuck
  • 234,037
  • 30
  • 302
  • 389
1

Based on @Sony's answer.

In case when you want to call the method method on some my_object and it's already overriden somewhere several classes higher (like for the Net::HTTPRequest#method), instead of doing .superclass.superclass.superclass use the:

Object.instance_method(:method).bind(my_object)

Like this:

p Object.instance_method(:method).bind(request).call(:basic_auth).source_location
Nakilon
  • 34,866
  • 14
  • 107
  • 142