Re: The Case for Multiple-Inheritance



On 10/7/07, Trans <transfire@xxxxxxxxx> wrote:
On Oct 7, 8:42 am, "Austin Ziegler" <halosta...@xxxxxxxxx> wrote:
No, actually, it doesn't provide maximum code reusability. Ruby
supports a rich vocabulary and you're choosing to use a form that,
while clearly useful in some cases, is not right.
Yes it does, b/c if methods are placed in a class, the only reuse if
via a subclass.

You are 100% wrong here. Not all reuse is defined by mixin or
inheritance. Delegation and composition are also reuse.

If they are in a module they are not limited by that constraint. I
haven't lost anything at all by putting all behavior in modules, I
have only gained. The approach is a superset.

The approach is a mess and tries to abstract things out in a nonsensical
way. Essentially, you're saying that UP FRONT you divide things into one
or more "class modules" and one or more "instance modules". With few
exceptions, modules should be extracted from classes when you can think
of a more-generic case for it. And you don't extract the whole damned
class to pull it off; you pull the special-purpose-for-similar-objects
code out.

I seem to be the only one who ever gives code examples. How about you
show me an example of how you'd do it?

You've got plenty of examples of how I'd do it: it's called my existing
Ruby code that's out there publicly on RubyForge. (This is probably
close to ten thousand lines of code ... that doesn't do what you're
talking about except in one instance I can think of that I only did it
that way for clarity and wouldn't do it that way again.)

I mostly do it as classes. I don't screw around with modularizing things
that simply *aren't* modules. Just because you CAN extract all of the
purpose out of a class and put it into a module just to include it right
back in doesn't mean you SHOULD.

Modules in Ruby are useful for adding new "generic" class
capabilities.

Enumerable is a way of using the ability to iterate over a collection
object (and a collection is defined by #each, which goes through the
*state values* of the object in turn). It's like a Java interface
except that you don't need to reimplement each and every piece of the
interface because the interface is always expressed in terms of
#each.

Transaction::Simple is a way of adding "extra" state to an object
that allows it to be versioned in memory. All of that extra state is
managed by the methods defined in the module.

What you're talking about is on par with components and graphical
development. They can work in simple cases, but the moment you start
having complex cases, you start realizing that the code is becoming a
bit more complex to integrate that way. You can either refactor your
code, or start looking at ways that the language can change to
accomodate your model's inflexibility.

Modules aren't really meant for providing state that the object
depends on normally. They're *extra*. So you should be working with
classes that have implementations; you should re-factor out common
functionality (and I mean REALLY common functionality) into modules;
you should have a class hierarchy if it's appropriate; you should
compose multiple objects into a single object where appropriate.
You are constraining the use of modules according to your own view of
how they "should" be used, and in the process I think you're missing
my point.

No, I didn't miss your point at all. I think your approach is stupid and
shortsighted. Sorry for the harshness, but the reality is that using
modules this way is nonsense and you're running into limitations because
you're trying to do something that doesn't make sense. I'm not saying
that Ruby's perfect or that everything in it makes sense, but if it
*hurts* to do something one way in Ruby, that's usually a sign that
you're doing it wrong.

There's HUGE code smell in what you've shown.

You've created an artificial separation between forms of code
encapsulation because, you reason to yourself, one is for handling
state and one if for generic capabilities.

It's not artificial. In Ruby, modules do not contain state. Period. Only
objects, which are instances of classes, contain state. The canonical
examples of modules (Enumerable, Comparable) don't deal with state
directly, but only through a defined interface that DOES deal with state
in an object. Transaction::Simple is a module because it adds functions
to objects that allow those objects to manipulate state in different
ways.

Transaction::Simple has generic applicability. Text::Format does not.

But that is putting a hard line in a soft world. There really is no
need to make that hard distinction. If a coder, like yourself, wants
to do that you can do so just as easily with a single form of
encapsulation....

[snip the rest of this nonsensical paragraph and the entire next
paragraph that has nothing to do with what I said]

Do NOT try to put words in my mouth.

I'll put it clearly: if I were running a Ruby consultancy and a
programmer of mine used your methodology for everything (e.g.,
classes defined by composing modules), I would not keep that
programmer on. It's a bad style. Sorry.
Clearly there is a reason you aren't running a consultancy.

...which has nothing to do with this stance. You write bad code and
design badly. You always want to change the language to fix the fact
that you've coded yourself into a corner. You've done this for years,
Trans.

Classes defined by composing modules is bad practice. There are times
for doing things like this, but they are few and far between and people
who do it should be prepared to defend their reasons for doing so
because it smells like bad code.

-austin
--
Austin Ziegler * halostatue@xxxxxxxxx * http://www.halostatue.ca/
* austin@xxxxxxxxxxxxx * http://www.halostatue.ca/feed/
* austin@xxxxxxxxxxx

.



Relevant Pages

  • Re: multiple inheritance
    ... slice" of functionality, and use MI to get at it from a class that has this ... to think much more about the design at this level than any most programmers ... I'm a MI AND Interface fan. ... Point 1: Aggregation ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Great SWT Program
    ... orthogonal to whether or not a program has a decent user interface. ... A few also knew the arrow keys existed. ... "useful functionality required to qualify the application as an IDE". ... Or maybe you simply use "real text editor" as a synonym for IDE; ...
    (comp.lang.java.programmer)
  • Re: Does Python really follow its philosophy of "Readability counts"?
    ... Separating an interface from its implementation reduces the ... whatever reason, it's unwilling to reveal to me. ... And `enforced data hiding' just slams ... Irrelevant for read-only inspection. ...
    (comp.lang.python)
  • Re: Ensuring a method exists
    ... When different classes offer similar functionality and you want ... Interface types are more flexible than class types because the former ... (defgeneric rem (collection object)) ... It's left up to the responsibility of the programmer to define the right methods, or to leave them out when they are actually not necessary. ...
    (comp.lang.lisp)
  • Re: When would you use an abstract class and when an interface?
    ... An abstract class is useful when you need a substantial amount of ... An example of where an interface is useful is where you have unrelated ... items that need to provide some similar functionality in a uniform ... but where the system caches them to disc as well as HTML ...
    (comp.lang.php)