Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Re: Solving the SUPER problem in Mixins with String Eval

by SpanishInquisition (Pilgrim)
on Oct 11, 2004 at 17:30 UTC ( [id://398224]=note: print w/replies, xml ) Need Help??


in reply to Solving the SUPER problem in Mixins with String Eval

You appear to be using the "inheritance is my hammer" ideology... Lemme try to explain. Maybe it's just me, but I seem to have managed to unlearn much of my OO schooling due to seeing industry abuses of it, and have rediscovered how to make OO fun again.

I see over-reliance on inheritance as one of the major pitfalls of OO design. When you see something complicated, the right thing to do is not to hack around it to make a more complicated solution, but to step back, look at the design, and clean it up. In this case, inheritance is your hammer, but the solution appears to be composition and chaining objects together.

If you are making a FooBarThing, don't let it extend FooThing and BarThing, or mixin Foo or Bar and subclass Thing, it doesn't have to be so complicated.

Have a MetaThing that takes any array of Things, and (though some combination functions) runs them together. If Things were Filters, a FooBarThing might run the filter results of Foo into a Bar, for example. This can even be totally dynamic, as in MetaThing(new FooThing,new BarThing).

If FooThing and BarThing are not sufficiently alike to have a common superclass, we have a problem, and we appear to be going down the mixin path. But I have found that if you make your objects real enough (nothing like Base without knowing what a Base really IS), you don't go down the mixin path.

I can go on further, but in case this doesn't make sense I'll wait and see if anyone understands what I've just said. The basic idea is "inheritance is only one tool in OO; and it is overused -- we can blame some of this on bad schooling from Java -- KISS still applies". If the mighty hammer of composition/encapsulation and polymorphism were used at an equal level as inheritance to solve design problems, much of the world's code would be a lot simpler and more maintainable.

As we go to further and further extents to make OO feel right, we lose the grasp of what OO is supposed to be. Keep it simple, design such that these situations do not occur, and when they do (and they will), find simple solutions out without symbol table manipulation and evals and such -- it is better to keep things clean and basic.

Anyhow, by no means am I an expert in my theory, and it's not the only way, but I do find OO much less distasteful when I start to temper the inheritance-hierachy thoughts that are so common these days, and start to put order back into designs. OO design that can't be articulated in simple diagrams can't succeed. The entire black box concept can't devolve into the "great ball of mud" designs java programs face. Anyhow, this has little to do with simon...but it's an interesting thing to watch. Using inheritance as the proverbial hammer is a gateway drug to overcomplicated interfaces. Mix in sic some functional programming, and remember what procedural programming taught you about simplicity being the only way to maintaince. And by no means build a shoehorn. Ever. (Unless you run a cobbler shop)

Replies are listed 'Best First'.
Re^2: Solving the SUPER problem in Mixins with String Eval
by stvn (Monsignor) on Oct 11, 2004 at 19:58 UTC
    I see over-reliance on inheritance as one of the major pitfalls of OO design

    Personally, I think that a better more general was to say that is, "The mis-use of inheritance is one of the major pitfalls of OO Design". Over-reliance is only one of the problems out there, under-reliance can be just as bad (when people don't understand when to use it, rather then just not knowing when not to use it).

    I agree with a lot of what you are saying, there is far to much inheritance shoehorning going on these days (although that is not really what simonm is doing, you might want to look closer at the implementation in Text::MicroMason (make sure you are looking at the latest developer release)). I have always felt that inheritance is best when it is employed in seperate clusters of shallow heirarchies which (usually) are not related to one another (a.k.a. highly decoupled).

    ... I can go on further, but in case this doesn't make sense I'll wait and see if anyone understands what I've just said.

    What you just described is actually an excellent case for a specific style of inheritance. Interface Polymorphism is IMO of the great underused and misunderstood aspects of OO programming.

    To do what you describe (have a MetaThing which takes an array of Things and "runs" each of them in turn) it is usually a good idea to have a common base which all Things are derived from. If for no other reason then for MetaThing to be able to indentify each Thing as a Thing. The knee-jerk approach is to make Thing::Base and have all Things inherit from it. However, this approach limits you in several ways since all your Things must inherit from Thing::Base.

    However, a better solution to this all is to create a Thing interface. Then all MetaThing needs to know is that your Thing conforms to the Thing interface, everything else is irrelvant to MetaThing. The idea really is that you try not to program "to the class", but instead "program to the interface". I have found that thinking this way tends to lead to highly reusable code and very clean designs.

    -stvn
      Yep, we are saying the same thing -- perhaps in different accents, but basically the same thing. At least the way you interpret the Things is the way I meant to explain them. As far as interfaces go, I'm not sure if I agree with the uber-dynmaticity of it all, but that's the way classes in Ruby work...you test to see if something responds to a particular function, rather than seeing if an object is_a particular thing. Again, I'm not sure I totally buy it, but it's an interesting idea.
        Again, I'm not sure I totally buy it, but it's an interesting idea.

        Consider this (thoroughly untested) code:

        sub add_stuff_to_file { my ($filehandle, $stuff) = @_; ($stuff->isa('Iterable')) || die "Stuff must be iterable"; my $i = $stuff->iterator(); ($i->isa('Iterator')) || die "Stuff's iterator must be an Iterator +"; while ($i->hasNext()) { print $filehandle $i->next(); } }
        Now, consider the following code which uses it.
        serialize_stuff_to_file(Array::Iterator->new(@array)); serialize_stuff_to_file(ArrayOfArrays::Iterator->new(@array)); serialize_stuff_to_file(ArrayOfHashes::Iterator->new(@array)); serialize_stuff_to_file(Hash::Iterator->new(%hash)); serialize_stuff_to_file(HashOfHashes::Iterator->new(%hash)); serialize_stuff_to_file(HashOfArrays::Iterator->new(%hash)); serialize_stuff_to_file(Tree::Iterator->new($tree));
        Since I know the Iterator will always respond to the same methods, and always produce the expected result on each loop, I can ignore the underlying structure of the object being iterated over. IMO, this is where MJD's argument that foreach is an iterator breaks down.

        -stvn

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://398224]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (6)
As of 2024-03-28 22:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found