tags:

views:

381

answers:

3

I have some base class A with a method that is not to be overridden.

class A
  def dont_override_me
    puts 'class A saying, "Thank you for not overriding me!"'
  end
end

And another class B that extends A and tries to override the dont_override_me method.

class B < A
  def dont_override_me
    puts 'class B saying, "This is my implementation!"'        
  end
end

If I instantiate B and call dont_override_me, class B's instance method will be called.

b = B.new
b.dont_override_me # => class B saying, "This is my implementation!"

This is because of ruby's properties. Understandable.

However, how do I force the base class method dont_override_me to be non-overridable by it's derived classes? I could not find a keyword like final in java for ruby. In C++, the base class methods can be made non-virtual so that they become non-overridable by the derived classes. How do I achieve this in ruby?

+4  A: 

You can do it, by hooking the change event and changing it back, but it seems a bit smelly to me:

http://scie.nti.st/2008/9/17/making-methods-immutable-in-ruby

It's one of those things that sort of defines Ruby, so fighting against it seems a little pointless imo. If someone redefines something so it breaks horribly.. that's their problem ;-)

Steven Robbins
Great, I wonder why this isn't part of standard ruby API! I mean this scenario is very much common and yet it is not handled while designing the language...
Chirantan
Being able to override absolutely everything is one of the core principals of Ruby, so "handling" is would kind of go against it. You know how much the purists would complain if they put this into the core of Ruby :-)
Steven Robbins
:) Agreed. But if we have to add some code to object class every time we want to do this or use a gem, thats painful too. I was thinking if finalize method (as given by Gdeglin below), were a standard ruby API, that would have been great. This scenario must common while building frameworks in ruby
Chirantan
Remember though, this still doesn't protect you fully. Anyone who wanted to could require 'immutable' before they require your library, and redefine immutable_method as an alias for public. Ruby is open. Fundamentally open.
rampion
Then we will need to make immutable method immutable :)
Chirantan
I dont think that word means what you think it means ;)
Brian
Oh is it? From "define: immutable" on google - not subject or susceptible to change or variation in form or quality or nature. This is what I think immutable means... In this context, this means the method is not supposed to be changed/overridden. Please correct me if I am wrong, I'm only a student
Chirantan
Immutable effectively just means "cannot be changed", so the usage is just fine in my book :-)
Steven Robbins
+3  A: 

Here's a way to do it: http://www.thesorensens.org/2006/10/06/final-methods-in-ruby-prevent-method-override/

This has also been packaged into a gem called "finalizer" (gem install finalizer)

This makes use of the method_added callback and compares the new method name with a list of methods that you wish to make final.

Gdeglin
A: 

I recommend:

class A #This is just as you've already defined it.
  def dont_override_me
    puts 'class A saying, "Thank you for not overriding me!"'
  end
end

module BehaviorForB
  def dont_override_me
    puts 'class B saying, "This is my implementation!"'        
  end

  def greet
    "Hello, Friend."
  end
end

class B < A
  include BehaviorForB
end

b = B.new
b.dont_override_me #=> class A saying, "Thank you for not overriding me!"
b.greet #=> Hello, Friend.

By keeping B's methods tucked away in an mixin, you get exactly what you desire. Any method of B's methods that are not already in A will be available. Methods that are already in A will not be overridden.

Mario