How can I force a subclass to implement a method in Ruby. There doesn't seem to be an abstract keyword in Ruby, which is the approach I would take in Java. Is there another more Ruby-like way to enforce abstract?
-
Additionally, Ruby uses something called Duck Typing: http://en.wikipedia.org/wiki/Duck_typing – mikeycgto Jul 22 '11 at 15:41
-
8@delnan, there was no need to phrase your answer like that. If I was trying to stick to a Java mindset I wouldn't be asking for a "Ruby-like" soltution. Thank you, however ,for you suggestion about the runtime exception. – Hunter McMillen Jul 22 '11 at 15:45
-
3I'm sorry if I came off rude. I've just seen *so many* people trying to program in language A as if it was language B. Your question seemed a bit like this too, as you asked how to do what abstract classes do in Java (instead of "an ruby equivalent to abstract classes" or something likr zhsz). Again, no offense meant, perhaps I got you wrong. – Jul 22 '11 at 15:50
7 Answers
Abstract methods are supposed to be less useful in Ruby because it's not strongly statically typed.
However, this is what I do:
class AbstractThing
MESS = "SYSTEM ERROR: method missing"
def method_one; raise MESS; end
def method_two; raise MESS; end
end
class ConcreteThing < AbstractThing
def method_one
puts "hi"
end
end
a = ConcreteThing.new
a.method_two # -> raises error.
It rarely seems to be necessary, however.
-
10
-
1+1, that's how it's done in Smalltalk with `subclassResponsibility` (`^ self subclassResponsibility`). – Michael Kohl Jul 22 '11 at 17:42
-
10If you just delete the entire contents of `AbstractThing`, you get the exact same behavior: an exception when trying to call `method_two`. In fact, you get a slightly *better* behavior, since instead of a generic non-descript, non-semantic `RuntimeError`, you get a `NoMethodError`, which tells you exactly what is wrong with your code. – Jörg W Mittag Jul 22 '11 at 21:26
-
6@Jorg. This is broadly true, except of course for two things -- first, I can raise whatever error I like; I just kept the example simple. The point is you get a more specific error. Second, defining the abstract class makes your intentions very plain to anyone reading the code (especially if you subclass it multiple times, which is usually the case). – Andy Jul 23 '11 at 20:41
-
2This is not the same. If a method is abstract, you should get an error when class is loaded, not even needing to explicitly call the missing method. – Rok Kralj Jan 21 '13 at 16:30
-
You could also add self.abstract_class = true to first class To make it really really clear. – baash05 Jul 12 '13 at 05:22
-
@JonathanSterling, what do you call a weak typed then? I can't find any definition that would put ruby as a strongly typed language. What is see is that ruby cares about types as little as possible. – akostadinov Jul 25 '14 at 21:29
-
@Jörg I prefer Andy's solution because defining the method in the Abstract Class serves as documentation for implementation class author. – Wakeel Jul 01 '22 at 10:10
I like the answer by pvandenberk, but I would improve it as follows:
module Canine # in Ruby, abstract classes are known as modules
def bark
fail NotImplementedError, "A canine class must be able to #bark!"
end
end
Now if you make a class belonging to Canine
"abstract class" (ie. a class that has Canine
module in its ancestors), it will complain if it is found that #bark
method is not implemented:
class Dog
include Canine # make dog belong to Canine "abstract class"
end
Dog.new.bark # complains about #bark not being implemented
class Dog
def bark; "Bow wow!" end
end
# Now it's OK:
Dog.new.bark #=> "Bow wow!"
Note that since Ruby classes are not static, but always open to changes, Dog
class itself cannot enforce existence of #bark
methods, since it doesn't know when is it supposed to be finished. If you as a programmer do, it is up to you to test it at such time.

- 12,444
- 5
- 57
- 74
-
3I was searching for `NotImplementedError` and ran across [this](http://chrisstump.online/2016/03/23/stop-abusing-notimplementederror/). – Hakanai May 09 '18 at 04:15
-
1`NotImplementedError`'s intent is to signal that a method is not available on the current platform (e.g. calling an API on windows that only nix based systems have). https://ruby-doc.org/core-2.5.0/NotImplementedError.html – Damon Aw Dec 23 '19 at 19:50
My preferred approach is similar but slightly different... I prefer it as follows, because it makes the code self-documenting, giving you something very similar to Smalltalk:
class AbstractThing
def method_one; raise "SubclassResponsibility" ; end
def method_two; raise "SubclassResponsibility" ; end
def non_abstract_method; method_one || method_two ; end
end
Some people will complain that this is less DRY, and insist on creating an exception subclass and/or put the "SubclassResponsibility"
string in a constant, but IMHO you can dry things up to the point of being chafed, and that is not usually a good thing. E.g. if you have multiple abstract classes across your code base, where would you define the MESS
string constant?!?

- 2,788
- 1
- 18
- 15

- 4,649
- 2
- 26
- 14
-
How about beat em with a symbol :) then it's a constant that floats around, not a string in each case. Like your answer. – baash05 Jul 12 '13 at 05:16
-
only objection, is that the sub classes would have to implement no_abstract_method too, else when it was called (presumably to test), method one would be called, and method 2 might be called. – baash05 Jul 12 '13 at 05:18
I like the use of a gem like abstract_method which gives a dsl rails style syntax abstract methods:
class AbstractClass
abstract_method :foo
end
class AbstractModule
abstract_method :bar
end
class ConcreteClass < AbstractClass
def foo
42
end
end

- 1,349
- 10
- 21
This code will not let you load the class if the methods 'foo', 'bar' and 'mate' are not defined in the inherited class.
It does not account for classes being defined across many files, but lets get honest do many of us actually define class methods across many files? I mean if you don't count mix-ins. (which this does account for)
def self.abstract(*methods_array)
@@must_abstract ||= []
@@must_abstract = Array(methods_array)
end
def self.inherited(child)
trace = TracePoint.new(:end) do |tp|
if tp.self == child #modules also trace end we only care about the class end
trace.disable
missing = ( Array(@@must_abstract) - child.instance_methods(false) )
raise NotImplementedError, "#{child} must implement the following method(s) #{missing}" if missing.present?
end
end
trace.enable
end
abstract :foo
abstract :bar, :mate

- 4,394
- 11
- 59
- 97
If you want to have an error thrown when you create an instance of the class you could do the following
class AbstractClass
def self.new(args)
instance = allocate # make memory space for a new object
instance.send(:default_initialize, args)
instance.send(:initialize, args)
instance
end
#This is called whenever object created, regardless of whether 'initialize' is overridden
def default_initialize(args)
self.abstract_method #This will raise error upon object creation
end
private :default_initialize
def initialize(args)
# This can be overridden by new class
end
end
class NewClass < AbstractClass
end
NewClass.new #Throw error

- 16,622
- 18
- 74
- 112

- 301
- 3
- 5
Because the question is (focus on) "How can I force a subclass to implement a method in Ruby", so i think we can use TDD :D, for example: rspec shared example
shared_examples "MUST implement abstract method" do |method_sym|
it { is_expected.to respond_to(method_sym) }
end
describe Stack do
it_behaves_like "MUST implement abstract method", :push
it_behaves_like "MUST implement abstract method", :pop
end
Maybe Tests are better than Abstract
:D , reference: http://morningcoffee.io/interfaces-in-ruby.html

- 3,405
- 2
- 9
- 20