The dark side of inherited methods

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 to lay down the law, because there will always be exceptions, but I thought Robert Klemme describes it pretty good a few messages back with the "is a" check.

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).

ActiveRecord is an interesting case of Rubyish inheritance too. It's really a focused DSL, I think. You inherit from ActiveRecord::Base to get a bunch of macros (has_many(), validates_presence_of(), etc.). Using this mini-DSL you describe your model and that changes how the objects produced from that class will behave. It's a build-your-on-class-with-shortcuts system, I think.

James Edward Gray II

···

On Nov 2, 2010, at 12:02 PM, Josh Cheek wrote:

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

Neither are required though, since Struct.new() takes a block:

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

James Edward Gray II

···

On Nov 2, 2010, at 1:04 PM, Joel VanderWerf wrote:

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).

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.

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.

There are, IIRC, two places where is a, is not well implemented by inheritance.

One is the classic square and rectangle problem. In a graphics library, both square and rectangle are graphic objects that can be drawn on the screen, moved and resized etc. But what is the relationship between square and rectangle? Is a square a rectangle with height = width, or is a rectangle a square without the constraint of height = width, or does is-a not apply at all? Whatever the author of the package chooses the users have to know if they have a square or a rectangle, or some very reasonable code sequences will fail to do what is expected.

x.width *= 2;
x.height *= 2;
If x is a rectangle this doubles both dimensions.
if x is a square, this will quadruple the dimensions, or fail.

The other is where the inheriting object has to learn a new skill at run time. A teachable foo is not a foo.

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.

IIRC, (I started back in the day also), it was promoted as a way to achieve data migration. You altered the schema, and altered the class to match, but only converted the data if it was edited. It was helpful in situations where just *linking* the OLTP took 36 hours, and updating all the data would have meant the service was down for days - too expensive to contemplate.

Regards
Ian

···

On 02/11/2010 17:40, Robert Klemme wrote:

On 02.11.2010 17:37, Intransition wrote:

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

> 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.

Mixins are just another way to do inheritance. It has the same issues.
The only difference is the module level --and that's just an arbitrary
deviation often circumvented by "ClassMethods" hacks..

To the main point of Ruby's poor handling of inheritance, I should
give an an example. Consider creating a subclass of Numeric. We have
no access to the `Numeric.new`, so a subclass of Numeric is actually a
trick. Such a class would (by necessity) work just as well without the
numeric superclass. The only reason for the superclass is so that
`is_a?(Numeric)` will work.

> 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.

I think implementation inheritance becomes easier if classes are kept
small with simple APIs and focused on a limited goal. Then larger
"real world" classes are built up by inheriting from these smaller
abstractions. But to have a really robust system to do this, one needs
some tools that Ruby doesn't provide, such a private inheritance,
probably class private instance variables and methods, and better
multiple inheritance than Ruby's mixin system.

I think there is a place for both inheritance and composition. It's
not an all or nothing deal. I think Enumerable is actually a great
example of the power of inheritance when used well. And I think Ruby
would be even better if it took that idea and ran with it a bit
further.

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.

Agreed.

···

On Nov 2, 1:40 pm, Robert Klemme <shortcut...@googlemail.com> wrote:

On 02.11.2010 17:37, Intransition wrote:

How do you fix this?

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

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

a = A.new
a.x = 1 # NoMethodError

···

On 11/02/2010 11:12 AM, James Edward Gray II wrote:

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

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.

There are, IIRC, two places where is a, is not well implemented by
inheritance.

One is the classic square and rectangle problem. In a graphics library, both
square and rectangle are graphic objects that can be drawn on the screen,
moved and resized etc. But what is the relationship between square and
rectangle? Is a square a rectangle with height = width, or is a rectangle a
square without the constraint of height = width, or does is-a not apply at
all?

The rule is pretty easy: state of subclasses can be separated in two groups:

1. state present in superclass
2. everything not in 1

Now the rule to maintain "is a" relationship is simple: the set of
allowed states in group 1 must be a subset of the set of allowed
states in the superclass (not a proper subset, so both may be
identical). Allowed state in group 2 is totally governed by the
subclass's invariant.

From this it follows immediately that, if inheritance is used here,
Square can only be a subclass of Rectangle and not the other way
round.

Whatever the author of the package chooses the users have to know if
they have a square or a rectangle, or some very reasonable code sequences
will fail to do what is expected.

x.width *= 2;
x.height *= 2;
If x is a rectangle this doubles both dimensions.
if x is a square, this will quadruple the dimensions, or fail.

A square _is a_ rectangle where width == height. That's the
definition in math and that's how I would implement it usually. The
simplest version would be

class Rectangle
  attr_reader :width, :height

  def initialize(width, height)
    @width = width
    @height = height
  end

  def outline
    2 * ( width + height )
  end
end

class Square < Rectangle

  def initialize(x)
    @width = x
  end

  def height; width; end
end

Note that in Ruby, different than in other programming languages,
@height is not wasted in a Square because it is never allocated. In
other languages you would simply ensure that both members had the same
value all the time in class Square.

Now if you need mutable squares and rectangles you need to devise a
method to manipulate Rectangle which can be used by subclasses as
well, e.g.

class Rectangle
  def resize(width, height)
    raise ArgumentError if width < 0 || height < 0
    @width = width
    @height = height
    self
  end
end

class Square
  def resize(width, height)
    raise ArgumentError if width < 0 || height < 0 || width != height
    @width = width
    self
  end
end

In a more realistic example you would probably make Rectangle inherit
Polygon and have completely different code for outline calculation and
manipulation. Then also there would be a generalized storage of side
lenghts and angles which would cope with arbitrary many sides thus not
wasting space for a member that is not used.

The other is where the inheriting object has to learn a new skill at run
time. A teachable foo is not a foo.

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.

IIRC, (I started back in the day also), it was promoted as a way to achieve
data migration. You altered the schema, and altered the class to match, but
only converted the data if it was edited. It was helpful in situations where
just *linking* the OLTP took 36 hours, and updating all the data would have
meant the service was down for days - too expensive to contemplate.

Wow, that's an amazing roundtrip time! I guess that situation has
changed dramatically nowadays (unless, that is, you have to compile
and link SAP maybe :-)).

Kind regards

robert

···

On Tue, Nov 2, 2010 at 11:44 PM, Ian Hobson <ian.hobson@ntlworld.com> wrote:

On 02/11/2010 17:40, Robert Klemme wrote:

On 02.11.2010 17:37, Intransition wrote:

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

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

What I would like to have are Mixins (especially Enumerable) behaving some
more clever.

Asume I have some MyCollection class. I implement #each and include
Enumerable. Now I can do:

mc = MyCollection.new('some', 'data', 'here', 'and', 'there')
mc4 = mc.select { |s| s.length != 4 }

But, unfortunately, mc4.class is Array and not MyCollection. I have to
implement select, reject and others by myself, loosing some of the nice help
Enumerable gives me.

I often want to chain things and call some mapping method on some collection
class without falling back to Array.

This could be solved if Enumerable looks for some MyCollection.newEnum()
class method and calls it if present to create a new object for collecting
the results of the select (or some other mechanism, not sure how to go
best. Any way to tell Enumerable how to collect the results of the mapping
method in a new MyCollection object will do).

Klaus

···

Intransition <transfire@gmail.com> wrote:

Mixins are just another way to do inheritance. It has the same issues.
The only difference is the module level --and that's just an arbitrary
deviation often circumvented by "ClassMethods" hacks..

--

The Answer is 42. And I am the Answer. Now I am looking for the Question.

> 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.

Mixins are just another way to do inheritance. It has the same issues.
The only difference is the module level --and that's just an arbitrary
deviation often circumvented by "ClassMethods" hacks..

To the main point of Ruby's poor handling of inheritance, I should
give an an example. Consider creating a subclass of Numeric. We have
no access to the `Numeric.new`, so a subclass of Numeric is actually a
trick. Such a class would (by necessity) work just as well without the
numeric superclass. The only reason for the superclass is so that
`is_a?(Numeric)` will work.

I am not sure I get your point. What do you mean by access to
Numeric.new? Method new is defined in Class and Numeric does not have
a method #initialize:

irb(main):028:0> Numeric.ancestors.map {|cl| cl.method(:new) rescue cl}
=> [#<Method: Class#new>, Comparable, #<Method: Class#new>, Kernel,
#<Method: Class#new>]

irb(main):029:0> Numeric.ancestors.map {|cl|
cl.instance_method(:initialize) rescue cl}
=> [#<UnboundMethod: Numeric(BasicObject)#initialize>, Comparable,
#<UnboundMethod: Object(BasicObject)#initialize>, Kernel,
#<UnboundMethod: BasicObject#initialize>]

Did you mean Integer? I describe the issue here
http://blog.rubybestpractices.com/posts/rklemme/019-Complete_Numeric_Class.html

Even that would only be a case of a specific class and not something
about inheritance in Ruby in general.

What is it that you find "poor" about inheritance in Ruby?

> 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.

I think implementation inheritance becomes easier if classes are kept
small with simple APIs and focused on a limited goal. Then larger
"real world" classes are built up by inheriting from these smaller
abstractions.

Makes me think of traits. Scala has some nice features in that area IIRC.

http://www.scala-lang.org/node/126

But to have a really robust system to do this, one needs
some tools that Ruby doesn't provide, such a private inheritance,
probably class private instance variables and methods, and better
multiple inheritance than Ruby's mixin system.

Exactly.

I think there is a place for both inheritance and composition. It's
not an all or nothing deal. I think Enumerable is actually a great
example of the power of inheritance when used well. And I think Ruby
would be even better if it took that idea and ran with it a bit
further.

What exactly would you like to have changed in the language? So far I
always liked the simplicity and cleanness of Ruby. But maybe
evolutions of the language are possible that will maintain the balance
yet get more out of inheritance. I am really curios what you are
imagining.

Kind regards

robert

···

On Thu, Nov 4, 2010 at 1:24 AM, Intransition <transfire@gmail.com> wrote:

On Nov 2, 1:40 pm, Robert Klemme <shortcut...@googlemail.com> wrote:

On 02.11.2010 17:37, Intransition wrote:

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

Completely share this impression and I agree that it is a pity.
I am not sure I completely agree with any opinion stated here but most
of them have made some points I was not completely aware of.

Cheers
R.

···

On Thu, Nov 4, 2010 at 1:24 AM, Intransition <transfire@gmail.com> wrote:

On Nov 2, 1:40 pm, Robert Klemme <shortcut...@googlemail.com> wrote:

On 02.11.2010 17:37, Intransition wrote:
> 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.

Mixins are just another way to do inheritance. It has the same issues.
The only difference is the module level --and that's just an arbitrary
deviation often circumvented by "ClassMethods" hacks..

To the main point of Ruby's poor handling of inheritance, I should
give an an example. Consider creating a subclass of Numeric. We have
no access to the `Numeric.new`, so a subclass of Numeric is actually a
trick. Such a class would (by necessity) work just as well without the
numeric superclass. The only reason for the superclass is so that
`is_a?(Numeric)` will work.

> 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.

I think implementation inheritance becomes easier if classes are kept
small with simple APIs and focused on a limited goal. Then larger
"real world" classes are built up by inheriting from these smaller
abstractions. But to have a really robust system to do this, one needs
some tools that Ruby doesn't provide, such a private inheritance,
probably class private instance variables and methods, and better
multiple inheritance than Ruby's mixin system.

I think there is a place for both inheritance and composition. It's
not an all or nothing deal. I think Enumerable is actually a great
example of the power of inheritance when used well. And I think Ruby
would be even better if it took that idea and ran with it a bit
further.

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.

Agreed.

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

Good question. It works to replace super with:

  self[:x] = new_x

I realize that's not an ideal solution though.

James Edward Gray II

···

On Nov 2, 2010, at 1:25 PM, Joel VanderWerf wrote:

On 11/02/2010 11:12 AM, James Edward Gray II wrote:

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

How do you fix this?

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

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

a = A.new
a.x = 1 # NoMethodError

I find it interesting that you change a two-argument Rectangle
initialization method to take one argument in Square, but you keep the
resize method as two arguments.

···

On Nov 3, 3:20 am, Robert Klemme <shortcut...@googlemail.com> wrote:

class Rectangle
attr_reader :width, :height

def initialize(width, height)
@width = width
@height = height
end

def outline
2 * ( width + height )
end
end

class Square < Rectangle

def initialize(x)
@width = x
end

def height; width; end
end

class Rectangle
def resize(width, height)
raise ArgumentError if width < 0 || height < 0
@width = width
@height = height
self
end
end

class Square
def resize(width, height)
raise ArgumentError if width < 0 || height < 0 || width != height
@width = width
self
end
end

--
-yossef

Of course there are ways that could be used to implement what you want, e.g.

module Enumerable
  # default: new behavior
  def select_2(cl = self.class)
    r = (cl.new rescue )
    each {|x| r << x if yield x}
    r
  end
end

But this does not solve the major issue that you change the interface.
Currently there is a ton of code around that works with the
assumption (explicit or implicit) that #select returns an Array. I
would not dare judge how much code will be broken if we change the
default behavior.

A solution would be this:

module Enumerable
  # default: old behavior
  def select_2(cl = Array)
    r = cl.new
    each {|x| r << x if yield x}
    r
  end
end

But then you loose the convenience to not have to provide the type.

Kind regards

robert

···

On Thu, Nov 4, 2010 at 9:45 AM, Klaus Stein <usenet@istik.de> wrote:

Intransition <transfire@gmail.com> wrote:

Mixins are just another way to do inheritance. It has the same issues.
The only difference is the module level --and that's just an arbitrary
deviation often circumvented by "ClassMethods" hacks..

What I would like to have are Mixins (especially Enumerable) behaving some
more clever.

Asume I have some MyCollection class. I implement #each and include
Enumerable. Now I can do:

mc = MyCollection.new('some', 'data', 'here', 'and', 'there')
mc4 = mc.select { |s| s.length != 4 }

But, unfortunately, mc4.class is Array and not MyCollection. I have to
implement select, reject and others by myself, loosing some of the nice help
Enumerable gives me.

I often want to chain things and call some mapping method on some collection
class without falling back to Array.

This could be solved if Enumerable looks for some MyCollection.newEnum()
class method and calls it if present to create a new object for collecting
the results of the select (or some other mechanism, not sure how to go
best. Any way to tell Enumerable how to collect the results of the mapping
method in a new MyCollection object will do).

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

I am not sure I get your point. What do you mean by access to
Numeric.new? Method new is defined in Class and Numeric does not have
a method #initialize:

That is what I am referring.

irb(main):029:0> Numeric.ancestors.map {|cl|
cl.instance_method(:initialize) rescue cl}
=> [#<UnboundMethod: Numeric(BasicObject)#initialize>, Comparable,
#<UnboundMethod: Object(BasicObject)#initialize>, Kernel,
#<UnboundMethod: BasicObject#initialize>]

Did you mean Integer? I describe the issue herehttp://blog.rubybestpractices.com/posts/rklemme/019-Complete_Numeric_...

No not Integer, although this holds for it too. Your HexNum is a
perfect example. Notice you never use #super in it's implementation.
Because you can't. Also try calling a Numeric method that you haven't
defined for HexNum, like #ceil.

Even that would only be a case of a specific class and not something
about inheritance in Ruby in general.

What is it that you find "poor" about inheritance in Ruby?

There are different things. For one I don't think the core classes are
well honed for inheritance, hence the original topic of this thread.

>> > 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.

> I think implementation inheritance becomes easier if classes are kept
> small with simple APIs and focused on a limited goal. Then larger
> "real world" classes are built up by inheriting from these smaller
> abstractions.

Makes me think of traits. Scala has some nice features in that area IIRC.

Redirecting…

> But to have a really robust system to do this, one needs
> some tools that Ruby doesn't provide, such a private inheritance,
> probably class private instance variables and methods, and better
> multiple inheritance than Ruby's mixin system.

Exactly.

> I think there is a place for both inheritance and composition. It's
> not an all or nothing deal. I think Enumerable is actually a great
> example of the power of inheritance when used well. And I think Ruby
> would be even better if it took that idea and ran with it a bit
> further.

What exactly would you like to have changed in the language? So far I
always liked the simplicity and cleanness of Ruby. But maybe
evolutions of the language are possible that will maintain the balance
yet get more out of inheritance. I am really curios what you are
imagining.

* Getting rid of class vs. module distinction.
* Have #include (or another method) provide "class level" methods in
inheritance chain.
* Private inclusion, such that all methods of class/module being
included are private to the including class/module.
* (Maybe) class private methods and variables, i.e. methods not
visible to the inheritance chain.
* Built-in method to mean `self.class.new()` --I think people forget
to do it that way.
* Built-in support for parametric mixins.
* Work on improving modularity of core library (e.g. Facet's Indexable
and Hashery's Ostructable).

I'm sure there are others too. And it's not an all or nothing deal.
Any one of them would improve upon things.

I agree about the simplicity. In fact, in some ways I want it to be
even more so.

···

On Nov 4, 4:47 am, Robert Klemme <shortcut...@googlemail.com> wrote:

... as is wasting a class because one wants to spare the typing IMHO. :slight_smile:

Kind regards

robert

···

On Tue, Nov 2, 2010 at 7:51 PM, James Edward Gray II <james@graysoftinc.com> wrote:

On Nov 2, 2010, at 1:25 PM, Joel VanderWerf wrote:

On 11/02/2010 11:12 AM, James Edward Gray II wrote:

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

How do you fix this?

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

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

a = A.new
a.x = 1 # NoMethodError

Good question. It works to replace super with:

self[:x] = new_x

I realize that's not an ideal solution though.

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

This is why I would not want this as _default_ behavior. I would expect
select, reject etc return an Array as it is now. But if the class including
Enumerable provides a _special_ MyCollection::enumNew method it would be
used instead.

So something like

module Enumerable
  def select
    r = (self.class.enumNew(self) rescue )
    # [ rest of the select code ]
  end
end

would do. This should not break old code.
I am not sure how to implement this best, as creating an empty collection
and adding elements by << ma be not the most efficient way to go.

(please note that MyCollection.enumNew takes the original object as
parameter to be able to copy other instance variables etc)

kind regards,

Klaus

···

Robert Klemme <shortcutter@googlemail.com> wrote:

Of course there are ways that could be used to implement what you want, e.g.

module Enumerable
  # default: new behavior
  def select_2(cl = self.class)
    r = (cl.new rescue )
    each {|x| r << x if yield x}
    r
  end
end

But this does not solve the major issue that you change the interface.
Currently there is a ton of code around that works with the
assumption (explicit or implicit) that #select returns an Array. I
would not dare judge how much code will be broken if we change the
default behavior.

--

The Answer is 42. And I am the Answer. Now I am looking for the Question.

My suggestion is not just for reducing typing: the super construct gives you a clean, idiomatic way to wrap the methods provided by Struct.

Anyway, it's not as if Class.new were depleting the ozone layer or something :slight_smile:

···

On 11/03/2010 01:22 AM, Robert Klemme wrote:

... as is wasting a class because one wants to spare the typing IMHO. :slight_smile:

But this does not solve the major issue that you change the interface.
Currently there is a ton of code around that works with the
assumption (explicit or implicit) that #select returns an Array. I
would not dare judge how much code will be broken if we change the
default behavior.

This is why I would not want this as _default_ behavior. I would expect
select, reject etc return an Array as it is now. But if the class including
Enumerable provides a _special_ MyCollection::enumNew method it would be
used instead.

So something like

module Enumerable
def select
r = (self.class.enumNew(self) rescue )
# [ rest of the select code ]
end
end

would do. This should not break old code.

It will, because classes can be modified in Ruby.

require 'set'

class Set
  def self.enum_new(other_set)
    new
  end
end

require 'a_library_that_uses_set'

...

x = a_set.select {|x| x > 0}
assert { Array === x } # boom!

Again, global state (in this case a method in class Set) bytes. My
suggested approach with providing the class as argument is better IMHO
because

- It is more flexible (at one time you can map an Array to a Set,
another time to an Array etc.).

- It does not break old code (see above).

Actually you do not want to determine the return type of Set#map
*globally* but rather per *use*.

I am not sure how to implement this best, as creating an empty collection
and adding elements by << ma be not the most efficient way to go.

There is no other way because you do not know beforehand whether all
or only part of the elements of the current collection go into the new
one.

(please note that MyCollection.enumNew takes the original object as
parameter to be able to copy other instance variables etc)

I noticed that but this is useless without knowing what the copy will
be used for. Enumerable#map and #select have vastly differing
semantics!

Cheers

robert

···

On Thu, Nov 4, 2010 at 10:55 AM, Klaus Stein <usenet@istik.de> wrote:

Robert Klemme <shortcutter@googlemail.com> wrote:

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

... as is wasting a class because one wants to spare the typing IMHO. :slight_smile:

My suggestion is not just for reducing typing: the super construct gives you
a clean, idiomatic way to wrap the methods provided by Struct.

That's true. It's just that it feels itchy to me to use a class this way.

Anyway, it's not as if Class.new were depleting the ozone layer or something
:slight_smile:

Hmm... What about global warming? :wink:

Cheers

robert

···

On Wed, Nov 3, 2010 at 9:58 PM, Joel VanderWerf <joelvanderwerf@gmail.com> wrote:

On 11/03/2010 01:22 AM, Robert Klemme wrote:

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