Reputation: 2589
In Ruby, super
is a keyword rather than a method.
Why was it designed this way?
Ruby's design tends toward implementing as much as possible as methods; keywords are usually reserved for language features that have their own grammar rules. super
, however, looks and acts like a method call.
(I know it would be cumbersome to implement super
in pure Ruby, since it would have to parse the method name out of caller
, or use a trace_func. This alone wouldn't prevent it from being a method, because plenty of Kernel's methods are not implemented in pure Ruby.)
Upvotes: 9
Views: 382
Reputation: 35318
It behaves a little differently, in that if you don't pass arguments, all of the current arguments (and block, if present) are passed along... I'm not sure how that would work as a method.
To give a rather contrived example:
class A
def example(a, b, c)
yield whatever(a, b) + c
end
end
class B < A
def example(a, b, c)
super * 2
end
end
I did not need to handle the yield, or pass the arguments to super
. In the cases where you specifically want to pass different arguments, then it behaves more like a method call. If you want to pass no arguments at all, you must pass empty parentheses (super()
).
It simply doesn't have quite the same behaviour as a method call.
Upvotes: 5
Reputation: 3716
super
doesn't automatically call the parent class's method. If you imagine the inheritance hierarchy of a ruby class as a list, with the class at the bottom and Object
at the top, when ruby sees the the super
keyword, rather than just check the the parent class, it moves up the entire list until it finds the first item that has a method defined with that name.
I'm careful to say item because it could also be a module. When you include a module in to a class, it is wrapped in an anonymous superclass and put above your class in the list I talked about before, so that means if you had a method defined for your class that was also defined in the module, then calling super from the class's implementation would call the module's implementation, and not the parent class's:
class Foo
def f
puts "Foo"
end
end
module Bar
def f
puts "Bar"
super
end
end
class Foobar < Foo
include Bar
def f
puts "Foobar"
super
end
end
foobar = Foobar.new
foobar.f
# =>
# Foobar
# Bar
# Foo
And I don't believe that it is possible to access this 'inheritance list' from the ruby environment itself, which would mean this functionality would not be available (However useful it is; I'm not every sure if this was an intended feature.)
Upvotes: 1
Reputation: 33954
Hm, good qustion. I'm not sure how else (besides using super
) you would you reference the super version of a given method.
You can't simply call the method by name, because the way that polymorphism works (how it figures out which version of that method to actually call, based on the object class) would cause your method to call itself, spinning into an infinite set of calls, and resulting in a stack overflow.
Upvotes: 0