views:

229

answers:

2

In my quest to transition from a decade of C++ to Ruby, I find myself second guessing how to accomplish the simplest things. Given the classic shape derivation example below, I'm wondering if this is "The Ruby Way". While I believe there's nothing inherently wrong with the code below, I'm left feeling that I'm not harnessing the full power of Ruby.

class Shape
  def initialize
  end
end

class TwoD < Shape
  def initialize
    super()
  end

  def area
     return 0.0
  end
end

class Square < TwoD
  def initialize( side )
    super()
    @side = side
  end

  def area
    return @side * @side
  end
end

def shapeArea( twod )
  puts twod.area
end

square = Square.new( 2 )

shapeArea( square ) # => 4

Is this implemented "The Ruby Way"? If not, how would you have implemented this?

+5  A: 

The beautiful thing about Ruby is you don't have to use inheritance just to provide a contract of implemented methods. Instead, you could have done this:

class Square
  def initialize(side)
    @side = side
  end

  def area
    @side * @side
  end
end

class Circle
  def initialize(radius)
    @radius = radius
  end

  def area
    @radius * @radius * 3.14159
  end
end

shapeArea(Square.new(2))
shapeArea(Circle.new(5))

This is a feature known as duck typing. So long as twod has an area method (in Ruby parlance we'd say twod responds to area), you're good to go.

Pesto
+3  A: 

The first answer is "the ruby way", but if you're feeling the change from C++ (highly-typed) to ruby (duck-typing) you can make it feel more like home:

class TwoD < Shape
  ...
  def area
    # make this truly look pure-virtual
    raise NoMethodError, "Pure virtual function called"
  end
end

Of course you're transitioning to ruby so you could also avoid repeating yourself:

class Module
  def pure_virtual(*syms)
    syms.each do |s|
      define_method(s) { raise NoMethodError, "Pure virtual function called: #{s}" }
    end
  end
end

class TwoD < Shape
  pure_virtual :area
  ...
end
Greg
I hate things like this. Just don't type `def area...` in the first place. It will already raise a no method error. Add a comment, you'll have to anyway to describe what `area` should do so that subclasses can implement it properly.
Logan Capaldo