>Yeah, I got it, you are a good C++ or java programmer and you look at ruby in contempt, seeing the title of this post. Well, don’t. The keyword “super” is not available in ruby (or an equivalent), but there are other (equally nice) methods.
Here again is our exact problem:
class A
def a
puts "A.a: #{b}"
end
def b
return "A.b"
end
end
Class B < A
def a
puts "B.a: B.b is #{b}. A.b is #{b}."
end
def b
return "B.b"
end
end
Now, the problem is that we want to make this code write “B.a: B.b is B.b. A.b is A.b.” on screen when we call “B.a“. In other terms, we want to be able to access a method in the superclass, which we have overriden.
I believe the simplest way to do this is to use the method Module::alias_method (remember that every object derives from this class because class class itself derives from it). Here is the solution:
class B < A
alias_method a_b, b
def a
puts "B.a: B.b is #{b}. A.b is #{a_b}."
end
def b
return "B.b"
end
end
There is a catch: we are cluttering the public namespace of class B with methods like a_b. So we actually want the to be private to our class:
class B < A
alias_method :a_b, :b
private :a_b
def a
puts "B.a: B.b is #{b}. A.b is #{a_b}."
end
def b
return "B.b"
end
end
The downside with this method is that the overriden method remains, and is actually callable using B.send(a_b). There is also a way to overcome this problem, if you really want to do so (I’ve seen this described in this and this):
class B < A
a_b = self.instance_method(:b)
def a
puts "B.a: B.b is #{b}. A.b is #{a_b.bind(self).call}."
end
def b
return "B.b"
end
end
You need to observe two things to understand this snippet:
- a_b has block scope, so even if you extend the class definition elsewhere, it will not be available to your fellow programmers unless they edit the file this code is in.
- It is exactly for the reason in 1 that we use define_method instead of regular def, since the latter starts a fresh scope (from which we cannot access a_b).
I believe #1 above is more of a nuisance than a feature. Here is an abstract example that would miserably fail (run ruby file2.rb):
file1.rb: ___________________________________
class A
def a
puts "A.a"
end
def b
return "A.b"
end
end
class B < A
old_b = self.instance_method(:b)
def a
puts "B.a b(): #{b}"
end
define_method(:b) do
return old_b.bind(self).call
end
end
file2.rb: ___________________________________
require "file1"
B.new.a
class B def c
puts "B.c: B.b is #{a_b.bind(self).call}"
end
end
B.new.c
Furthermore, objects are not component instances. The reuse unit in OO is the class, which is intended to define a type that is extendible. Access control works more as a program/design support mechanism (it’s reffered to as a “suggestion”) rather than a security mechanism.
With some hard work, I believe one can actually prevent private methods being called using send.
No time for that now. Maybe later..
PS: Blogger’s editor is a pain.