The dark side of inherited methods

Let's say I want to make a new class, Vector (that will function,
eventually, like R vectors for mathematical operations), and I write
this:

class Vector < Array
  def initialize(*arr)
    super(arr.flatten)
  end
end

v = Vector.new(1,2,3) # => [1, 2, 3]
v.class # => Vector
v.collect{|item| item * 3}.class # => Array
v.collect!{|item| item * 3}.class # => Vector

I noticed that I inherited the Array#collect and Array#collect!
methods. Yeah for inheritance! But then look at the returned classes.
Array#collect returns and array. Array.collect! returns a Vector. If
you look at the underlying C code that defines these methods the
response makes sense. Collect! alters the object itself using the
results from the block, while collect builds a new Array from the
results of the block. But geesh, that means to have consistent
behavior, I have to add the following (and worse, look through every
other Array method to determine if the return value should be a vector
rather than an array):

class Vector < Array
  def collect(&blk)
    Vector.new(super) #gets the return from super and puts that
back into a vector object
  end
end

v = Vector.new(1,2,3) # => [1, 2, 3]
v.class # => Vector
v.collect{|item| item * 3}.class # => Vector
v.collect!{|item| item * 3}.class # => Vector

When a method has the form of array -> an_array I want it to take a
vector -> a_vector, but I get vector -> array. Is there a simple way
to fix this for all similar methods? Or do I just have to live with
the dark side of inherited methods?
Thanks,
Tim

Define "consistent behavior". That #collect returns an Array is
consistent with other, similar language constructs. The question is if
you want an Array back, or want a Vector back from the operation you
perform. Similarly, since you inherited the Array methods, Vector#join
will behave exactly like Array#join.

That's pretty much the point of inheritance: Re-using a class's
methods to make your own life easier by reducing the work you need to
do, since most methods you expect to use are identical to what you
need, and only need adaptation to your own needs (via encapsulation,
or overriding, for example).

Maybe you have better success (i.e. less work), if you a) encapsulate
similar calls into calls of your own and massage the operation that
way, or b) you move one up in the inheritance change, and use
Enumerable to inherit from. Most work will be c) create your class
from scratch, and mix in Array or Enumerable.

TL;DR: Any class derived from another class will inherit its method.
That's true for Ruby, as it is for Java or C#. It's pretty much the
point of inheritance. :wink:

···

On Sun, Oct 31, 2010 at 11:30 PM, timr <timrandg@gmail.com> wrote:

I noticed that I inherited the Array#collect and Array#collect!
methods. Yeah for inheritance! But then look at the returned classes.
Array#collect returns and array. Array.collect! returns a Vector. If
you look at the underlying C code that defines these methods the
response makes sense. Collect! alters the object itself using the
results from the block, while collect builds a new Array from the
results of the block. But geesh, that means to have consistent
behavior, I have to add the following (and worse, look through every
other Array method to determine if the return value should be a vector
rather than an array):

--
Phillip Gawlowski

Though the folk I have met,
(Ah, how soon!) they forget
When I've moved on to some other place,
There may be one or two,
When I've played and passed through,
Who'll remember my song or my face.

It is a problem with inheritance and another reason why inheritance is almost never what we want. Luckily, this is Ruby where anything is possible:

class Vector < BasicObject
  def initialize(*array)
    @array = array.flatten
  end
  
  def class
    ::Vector
  end
  
  def method_missing(meth, *args, &blk)
    result = @array.send(meth, *args, &blk)
    if result.object_id == @array.object_id
      self
    elsif result.class == ::Array
      self.class.new(result)
    else
      result
    end
  end
end

v = Vector.new(1,2,3) # => [1, 2, 3]
v.class # => Vector
v.collect { |item| item * 3 }.class # => Array
v.collect!{ |item| item * 3 }.class # => Vector

That's a solution for Ruby 1.9, but a similar trick is possible with 1.8 using a touch more code. It's probably not perfect yet, but you get the idea.

James Edward Gray II

···

On Oct 31, 2010, at 5:30 PM, timr wrote:

Let's say I want to make a new class, Vector (that will function,
eventually, like R vectors for mathematical operations), and I write
this:

class Vector < Array
def initialize(*arr)
   super(arr.flatten)
end
end

v = Vector.new(1,2,3) # => [1, 2, 3]
v.class # => Vector
v.collect{|item| item * 3}.class # => Array
v.collect!{|item| item * 3}.class # => Vector

I noticed that I inherited the Array#collect and Array#collect!
methods. Yeah for inheritance! But then look at the returned classes.
Array#collect returns and array. Array.collect! returns a Vector.

Is there a simple way to fix this for all similar methods? Or do I just have to live with the dark side of inherited methods?

Scala solved this problem (which can viewed as a lack of the "uniform
return type principle") on its collection library on version 2.8:
http://www.scala-lang.org/docu/files/collections-api/collections_2.html

It used implicits arguments to do this. It is not a simple design, but
it is quite general.

···

--
Posted via http://www.ruby-forum.com/.

I see how Vector is-a Array, I don't see how Array is-a Vector? I would consider collect and collect! to be inconsistent under this definition.

···

On 10-10-31 06:42 PM, Phillip Gawlowski wrote:

On Sun, Oct 31, 2010 at 11:30 PM, timr<timrandg@gmail.com> wrote:

I noticed that I inherited the Array#collect and Array#collect!
methods. Yeah for inheritance! But then look at the returned classes.
Array#collect returns and array. Array.collect! returns a Vector. If
you look at the underlying C code that defines these methods the
response makes sense. Collect! alters the object itself using the
results from the block, while collect builds a new Array from the
results of the block. But geesh, that means to have consistent
behavior, I have to add the following (and worse, look through every
other Array method to determine if the return value should be a vector
rather than an array):

Define "consistent behavior". That #collect returns an Array is
consistent with other, similar language constructs. The question is if
you want an Array back, or want a Vector back from the operation you
perform. Similarly, since you inherited the Array methods, Vector#join
will behave exactly like Array#join.

That's pretty much the point of inheritance: Re-using a class's
methods to make your own life easier by reducing the work you need to
do, since most methods you expect to use are identical to what you
need, and only need adaptation to your own needs (via encapsulation,
or overriding, for example).

Maybe you have better success (i.e. less work), if you a) encapsulate
similar calls into calls of your own and massage the operation that
way, or b) you move one up in the inheritance change, and use
Enumerable to inherit from. Most work will be c) create your class
from scratch, and mix in Array or Enumerable.

TL;DR: Any class derived from another class will inherit its method.
That's true for Ruby, as it is for Java or C#. It's pretty much the
point of inheritance. :wink:

--
Kind Regards,
Rajinder Yadav | DevMentor.org | Do Good! ~ Share Freely

GNU/Linux: 2.6.35-22-generic
Kubuntu x86_64 10.10 | KDE 4.5.1
Ruby 1.9.2p0 | Rails 3.0.1

It is a problem with inheritance and another reason why inheritance is
almost never what we want.

Tim: Glad that I am not the only one who thinks inheritance has some
holes.
Tim: Note the corrected output from James Edward Gray II's response:

class Vector < Object
  def initialize(*array)
    @array = array.flatten
  end
  def class
    ::Vector
  end
  def method_missing(meth, *args, &blk)
    result = @array.send(meth, *args, &blk)
    if result.object_id == @array.object_id
      self
    elsif result.class == ::Array
      self.class.new(result)
    else
      result
    end
  end
end
v = Vector.new(1,2,3) # => #<Vector:0x10183c758
@array=[1, 2, 3]>
v.class # => Vector
v.collect { |item| item * 3 }.class # => Vector
v.collect!{ |item| item * 3 }.class # => Vector

That's a solution for Ruby 1.9, but a similar trick is possible with
1.8 using a touch more code. It's probably not perfect yet, but you
get the idea.

Tim: It actually runs fine in 1.8.7 just as you have it coded.
Tim: However, I already blew my method_missing to over-ride the
mathematical operators (see below):
Tim: But I get your approach and I will think about something along
those lines. It could also work to set up a proxy class and use its
method_missing (since I already used Vector's method_missing) to fix
the type returned the way you did. But that means v -
Vector.new(1,1,1); p_of_v = Proxy.new(v) every time I want to use a
vector. Still not ideal.

class Vector < Array
  undef :-, :+, :*, :==

  def initialize(*arr)
    v = super(arr.flatten)
  end

  def to_a
    Array.new(self)
  end

  def &(arg)
    Vector.new(super)
  end

  def |(arg)
    Vector.new(super)
  end

  def collect(&blk)
    Vector.new(super)
  end

  def select(&blk)
    Vector.new(super)
  end

  def method_missing(meth, arg)
    arg.class == Vector ? a2 = arg : a2 = Vector.new(arg)
    long, short = [self, a2].sort{|s,b| b.length <=> s.length}
    empty_collection = Array.new(long.length)

    arr_result = empty_collection.each_with_index.map do |item, ind|
      if self[ind%self.length] == nil || a2[ind%a2.length] == nil
#allow nils to be mathematically processed
        nil
      else
        self[ind%self.length].send(meth, a2[ind%a2.length])
      end
    end
    Vector.new(arr_result)
  end
end

Example Usage:
a = Vector.new([1,2,1,10])
b = Vector.new([2,5,1,7])
a - b # => [-1, -3, 0, 3]
a.uniq.class # => Vector
(a | b) # => [1, 2, 10, 5, 7]
(a | b).class # => Vector

<snip>

It is a problem with inheritance and another reason why inheritance is almost never what we want.

Completely agree with this. Apart of the code you suggested I would
like to tackle the problem on a conceptional level. Enumerable#map
returns arrays Period. What OP might want to do is something like this

module Sequence
  include Enumerable
  # A sequence is defined by
  # (i) How to traverse it
  # def each &blk
  # making sure that blk is called with exactly all elements of the
sequence in the
  # predefined order
  # (ii) How to append elements to it
  # def add new_element
  # creating a new sequence (or modifying in place)
  def map &blk
    inject(self.class.new) do | result, ele |
      result.add blk.( ele )
    end
  end
end # module Sequence

If OP had had this available the delegation would have worked quite well.

class Vector
   include Sequence
   def each; # as he needs (must yield all elements)
   def add; # as he needs (must return a Sequence)

No inheritance and yet quite some effective decomposition :stuck_out_tongue:

HTH
R.

···

On Mon, Nov 1, 2010 at 12:49 AM, James Edward Gray II <james@graysoftinc.com> wrote:

On Oct 31, 2010, at 5:30 PM, timr wrote:

--
There are worse things than having people misunderstand your work. A
worse danger is that you will yourself misunderstand your work.
-- Paul Graham

Eeep, method_missing. I was thinking this might be accomplished via
some sort of AOP. I looked at AspectR and Aquarium but couldn't make
it work. Maybe that's the wrong approach, though.

Regards,

Dan

···

On Oct 31, 5:49 pm, James Edward Gray II <ja...@graysoftinc.com> wrote:

On Oct 31, 2010, at 5:30 PM, timr wrote:

> Let's say I want to make a new class, Vector (that will function,
> eventually, like R vectors for mathematical operations), and I write
> this:

> class Vector < Array
> def initialize(*arr)
> super(arr.flatten)
> end
> end

> v = Vector.new(1,2,3) # => [1, 2, 3]
> v.class # => Vector
> v.collect{|item| item * 3}.class # => Array
> v.collect!{|item| item * 3}.class # => Vector

> I noticed that I inherited the Array#collect and Array#collect!
> methods. Yeah for inheritance! But then look at the returned classes.
> Array#collect returns and array. Array.collect! returns a Vector.
> Is there a simple way to fix this for all similar methods? Or do I just have to live with the dark side of inherited methods?

It is a problem with inheritance and another reason why inheritance is almost never what we want. Luckily, this is Ruby where anything is possible:

class Vector < BasicObject
def initialize(*array)
@array = array.flatten
end

def class
::Vector
end

def method_missing(meth, *args, &blk)
result = @array.send(meth, *args, &blk)
if result.object_id == @array.object_id
self
elsif result.class == ::Array
self.class.new(result)
else
result
end
end
end
v = Vector.new(1,2,3) # => [1, 2, 3]
v.class # => Vector
v.collect { |item| item * 3 }.class # => Array
v.collect!{ |item| item * 3 }.class # => Vector

That's a solution for Ruby 1.9, but a similar trick is possible with 1.8 using a touch more code. It's probably not perfect yet, but you get the idea.

That's a pretty extreme position to take. Inheritance is an indispensable
tool. That said, I will agree that "is a" relationships come up far less
frequently than 'has a" relationships.

I would say that it would make far more sense to create a Vector class which
"has a"(n) array, and make the Vector an Enumerable. Of course, what makes
even more sense is to use the Vector class provided by "require 'matrix'"

···

On Sun, Oct 31, 2010 at 5:49 PM, James Edward Gray II <james@graysoftinc.com > wrote:

It is a problem with inheritance and another reason why inheritance is
almost never what we want.

--
Tony Arcieri
Medioh! A Kudelski Brand

Array#collect returns a new Array. Array#collect! returns the existing
Array. Thus, Vector#collect returns a new Array, and Vector#collect!
returns the existing Vector. Bang-methods operate on the object
itself, and return the modified object, instead of creating a new
object containing the result of the operation the non-Bang-method
performed.

The behavior is consistent with how methods with and without Bang operate.

···

On Sun, Oct 31, 2010 at 11:54 PM, Rajinder Yadav <devguy.ca@gmail.com> wrote:

I see how Vector is-a Array, I don't see how Array is-a Vector? I would
consider collect and collect! to be inconsistent under this definition.

--
Phillip Gawlowski

Though the folk I have met,
(Ah, how soon!) they forget
When I've moved on to some other place,
There may be one or two,
When I've played and passed through,
Who'll remember my song or my face.

My first reaction when I saw the original code was, "Eeep, inheriting from a core class."

I guess we both have some fear to get past. :slight_smile:

James Edward Gray II

···

On Nov 1, 2010, at 4:32 PM, Daniel Berger wrote:

On Oct 31, 5:49 pm, James Edward Gray II <ja...@graysoftinc.com> > wrote:

On Oct 31, 2010, at 5:30 PM, timr wrote:

Let's say I want to make a new class, Vector (that will function,
eventually, like R vectors for mathematical operations), and I write
this:

class Vector < Array
def initialize(*arr)
   super(arr.flatten)
end
end

v = Vector.new(1,2,3) # => [1, 2, 3]
v.class # => Vector
v.collect{|item| item * 3}.class # => Array
v.collect!{|item| item * 3}.class # => Vector

I noticed that I inherited the Array#collect and Array#collect!
methods. Yeah for inheritance! But then look at the returned classes.
Array#collect returns and array. Array.collect! returns a Vector.
Is there a simple way to fix this for all similar methods? Or do I just have to live with the dark side of inherited methods?

It is a problem with inheritance and another reason why inheritance is almost never what we want. Luckily, this is Ruby where anything is possible:

class Vector < BasicObject
  def initialize(*array)
    @array = array.flatten
  end

  def class
    ::Vector
  end

  def method_missing(meth, *args, &blk)
    result = @array.send(meth, *args, &blk)
    if result.object_id == @array.object_id
      self
    elsif result.class == ::Array
      self.class.new(result)
    else
      result
    end
  end
end
v = Vector.new(1,2,3) # => [1, 2, 3]
v.class # => Vector
v.collect { |item| item * 3 }.class # => Array
v.collect!{ |item| item * 3 }.class # => Vector

That's a solution for Ruby 1.9, but a similar trick is possible with 1.8 using a touch more code. It's probably not perfect yet, but you get the idea.

Eeep, method_missing.

It is a problem with inheritance and another reason why inheritance is
almost never what we want.

I cannot speak for Edward but would like to defend my (+1) on this.
Actually there is nothing to defend because I did not read correctly
(good :(). I read inheritance from a "core class", which was not
written. And then I continued to read text that was not there:
"inheritance from a core class using delegation to #each".
That said I should probably apologize :P, so I do. But I guess that is
where the "problem" comes from.
Cheers
Robert

···

--
There are worse things than having people misunderstand your work. A
worse danger is that you will yourself misunderstand your work.
-- Paul Graham

It is a problem with inheritance and another reason why inheritance is
almost never what we want.

That's a pretty extreme position to take. Inheritance is an indispensable
tool. That said, I will agree that "is a" relationships come up far less
frequently than 'has a" relationships.

I believe this is what James wanted to stress: inheritance is used far
too often for purposes where it's not appropriate. A real is_a
relationship is pretty rare yet many people use inheritance,
especially with core / std lib classes as parents which almost always
is a code smell.

Side note: there are languages such as Eiffel and C++ which have
support for implementation inheritance (i.e. the interface changes
incompatibly from super class to sub class) and in those languages
inheritance can be used more often than in language which lack these
features (e.g. Java).

I would say that it would make far more sense to create a Vector class which
"has a"(n) array, and make the Vector an Enumerable. Of course, what makes
even more sense is to use the Vector class provided by "require 'matrix'"

Absolutely.

Kind regards

robert

···

On Tue, Nov 2, 2010 at 4:29 AM, Tony Arcieri <tony.arcieri@medioh.com> wrote:

On Sun, Oct 31, 2010 at 5:49 PM, James Edward Gray II <james@graysoftinc.com >> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

There have been a lot of books written about the evils of inheritance. It's mentioned on the Wikipedia page for inheritance. I thought it was pretty much a given at this point.

Of course, there are various forms of inheritance. It's "implementation inheritance" that's the main problem.

Design Patterns could also be called Ways to Avoid (Implementation) Inheritance, I think. I find that it's even easier and more desirable to avoid inheritance with a language as dynamic as Ruby.

Of course, inheritance has it's place and uses but I feel it's definitely overused.

James Edward Gray II

···

On Nov 1, 2010, at 10:29 PM, Tony Arcieri wrote:

On Sun, Oct 31, 2010 at 5:49 PM, James Edward Gray II <james@graysoftinc.com >> wrote:

It is a problem with inheritance and another reason why inheritance is
almost never what we want.

That's a pretty extreme position to take. Inheritance is an indispensable tool.

Thanks Phillip, yes I agree with respect to the implementation, i get it. was mulling that over after i hit send =P

···

On 10-10-31 07:00 PM, Phillip Gawlowski wrote:

On Sun, Oct 31, 2010 at 11:54 PM, Rajinder Yadav<devguy.ca@gmail.com> wrote:

I see how Vector is-a Array, I don't see how Array is-a Vector? I would
consider collect and collect! to be inconsistent under this definition.

Array#collect returns a new Array. Array#collect! returns the existing
Array. Thus, Vector#collect returns a new Array, and Vector#collect!
returns the existing Vector. Bang-methods operate on the object
itself, and return the modified object, instead of creating a new
object containing the result of the operation the non-Bang-method
performed.

The behavior is consistent with how methods with and without Bang operate.

--
Kind Regards,
Rajinder Yadav | DevMentor.org | Do Good! ~ Share Freely

GNU/Linux: 2.6.35-22-generic
Kubuntu x86_64 10.10 | KDE 4.5.1
Ruby 1.9.2p0 | Rails 3.0.1

My first reaction when I saw the original code was, "Eeep, inheriting
from a core class."

+1 (me too)

I guess we both have some fear to get past. :slight_smile:

Well, I don't think it is a question of fear. :slight_smile:

Cheers

  robert

···

On 01.11.2010 22:55, James Edward Gray II wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Indeed, I think inheritance gets a really bad rap in Ruby b/c Ruby's
base classes and inheritance system are so poorly designed to handle
it.

The other day I was talking to my Father, a Cobol programmer from back
in the day, and he was telling me that when he retired, OOP was just
starting to get hyped. He was quite interested in it at the time and
then rattled off some of the advantages he remembered it was to bring
to the field. Inheritance for code reuse was high on the list and
related to that, one point eally struck me -- instead of versioning
code as we have become accustomed, the idea was to subclass the
original class and implement changes in the subclass. Using some sort
of class name referencing scheme you could use any version. It sort of
reminded me of database migrations.

I imagined is something like:

  class Foo1
    ..
  end

  class Foo2 < Foo1
    ...
  end

  #pick a version
  Foo = Foo2

Sadly, I had to inform him that OOP did not quite prove to be the
godsend everyone originally thought it might be.

···

On Nov 2, 5:31 am, Robert Klemme <shortcut...@googlemail.com> wrote:

On Tue, Nov 2, 2010 at 4:29 AM, Tony Arcieri <tony.arci...@medioh.com> wrote:
> On Sun, Oct 31, 2010 at 5:49 PM, James Edward Gray II <ja...@graysoftinc.com > >> wrote:

>> It is a problem with inheritance and another reason why inheritance is
>> almost never what we want.

> That's a pretty extreme position to take. Inheritance is an indispensable
> tool. That said, I will agree that "is a" relationships come up far less
> frequently than 'has a" relationships.

I believe this is what James wanted to stress: inheritance is used far
too often for purposes where it's not appropriate. A real is_a
relationship is pretty rare yet many people use inheritance,
especially with core / std lib classes as parents which almost always
is a code smell.

Side note: there are languages such as Eiffel and C++ which have
support for implementation inheritance (i.e. the interface changes
incompatibly from super class to sub class) and in those languages
inheritance can be used more often than in language which lack these
features (e.g. Java).

Can you give some examples of where it has its place? I have been trying to
think of one, and can't. I realized the only time I ever subclass anything
is ActiveRecord::Base (and I'm not really sure what that offers over
modules, DataMapper uses modules, for example).

···

On Tue, Nov 2, 2010 at 11:19 AM, James Edward Gray II <james@graysoftinc.com > wrote:

Of course, inheritance has it's place and uses but I feel it's definitely
overused.

It is a problem with inheritance and another reason why inheritance is
almost never what we want.

That's a pretty extreme position to take. Inheritance is an indispensable
tool. That said, I will agree that "is a" relationships come up far less
frequently than 'has a" relationships.

I believe this is what James wanted to stress: inheritance is used far
too often for purposes where it's not appropriate. A real is_a
relationship is pretty rare yet many people use inheritance,
especially with core / std lib classes as parents which almost always
is a code smell.

Side note: there are languages such as Eiffel and C++ which have
support for implementation inheritance (i.e. the interface changes
incompatibly from super class to sub class) and in those languages
inheritance can be used more often than in language which lack these
features (e.g. Java).

Indeed, I think inheritance gets a really bad rap in Ruby b/c Ruby's
base classes and inheritance system are so poorly designed to handle
it.

I would not subscribe to that. Although Bertrand Meyer is a big fan of implementation inheritance I am not yet convinced that it is such a good idea so often. Of course, there are always uses for any technique present, but I find the "is a" relationship interpretation of inheritance so clear and obvious that I somehow feel bad about polluting inheritance with other uses. I cannot really put forward a more concrete argument or even back this up by some hard (business) numbers, but a world in which "A inherits B" <=> "A is a B" is so much simpler. And in Ruby, whenever you need implementation inheritance you can use a mixin module. Enumerable is a very good example for that.

The other day I was talking to my Father, a Cobol programmer from back
in the day, and he was telling me that when he retired, OOP was just
starting to get hyped. He was quite interested in it at the time and
then rattled off some of the advantages he remembered it was to bring
to the field. Inheritance for code reuse was high on the list and

Well, there are other forms of code reuse - even in procedural languages. It's not that you _need_ inheritance to have code reuse. I would even go as far as to claim that it is more difficult to implement classes intended solely for implementation inheritance than classes which implement a particular real world concept and which are only inherited if "is a" is needed. I say this because a class intended for implementation inheritance needs other criteria for including functionality than a class which implements a particular concept.

related to that, one point eally struck me -- instead of versioning
code as we have become accustomed, the idea was to subclass the
original class and implement changes in the subclass. Using some sort
of class name referencing scheme you could use any version.

That does not sound like a, um, proper application of inheritance to me. It might be useful to do it that way in some rare conditions but I would not promote this as a big feature of inheritance.

Sadly, I had to inform him that OOP did not quite prove to be the
godsend everyone originally thought it might be.

Well, silver bullets - if you know one, you know them all. :slight_smile:

Btw, I find that we have this type of discussion far too seldom here nowadays and I imagine that we did that more often earlier on. But that is totally subjective.

Cheers

  robert

···

On 02.11.2010 17:37, Intransition wrote:

On Nov 2, 5:31 am, Robert Klemme<shortcut...@googlemail.com> wrote:

On Tue, Nov 2, 2010 at 4:29 AM, Tony Arcieri<tony.arci...@medioh.com> wrote:

On Sun, Oct 31, 2010 at 5:49 PM, James Edward Gray II<ja...@graysoftinc.com >>>> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

The shortest example that occurs to me:

class A < Struct.new :x, :y, :z
   def length
     Math.sqrt(x**2 + y**2 + z**2)
   end
end

That only saves a couple of keystrokes compared to:

A = Struct.new :x, :y, :z
class A
...

but it's cleaner IMO. Also, it allows you to do this:

   def x=(new_x)
     raise ArgumentError if new_x > 100
     super
   end

In the "A=Struct.new" approach, you have to muck around with alias to get the same effect.

···

On 11/02/2010 10:02 AM, Josh Cheek wrote:

On Tue, Nov 2, 2010 at 11:19 AM, James Edward Gray II<james@graysoftinc.com >> wrote:

Of course, inheritance has it's place and uses but I feel it's definitely
overused.

Can you give some examples of where it has its place? I have been trying to
think of one, and can't. I realized the only time I ever subclass anything
is ActiveRecord::Base (and I'm not really sure what that offers over
modules, DataMapper uses modules, for example).