Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change

Re^2: A few Perl OOP questions. (disparaging)

by tye (Cardinal)
on Oct 22, 2003 at 20:50 UTC ( #301361=note: print w/ replies, xml ) Need Help??

in reply to Re: A few Perl OOP questions.
in thread A few Perl OOP questions.

my $class = ref( $type ) || $type;
[...]That is an idiom which is disparaged these days as too admissive of bugs.

It is disparaged by some people. I've repeatedly criticized people for disparaging it without specifying what one should replace it with. I find the most obvious way of not using it to be too likely to produce way-too-confusing errors:

package Purified::Confusion; sub new { # my $proto = shift(@_); # my $class = ref($proto) || $proto; # To restore sanity, replace the line below # with the above two commented lines. my $class = shift(@_); bless [@_], $class; } sub get { my $self = shift(@_); return @$self if ! @_; return @{$self}[@_]; } 1;
#!/usr/bin/perl -w use strict; use Purified::Confusion; my $one= Purified::Confusion->new('a'); print $one->get(), $/; # A quite common idiom in Perl code # which produces no errors nor warnings: my $two= $one->new('b'); # ...but that produces not at all what is desired, # if the module author heeded the FUD; as we see here: print $two->get(), $/;
produces the following output:
a Can't locate object method "get" via package "Purified::Confusion=ARRA +Y(0x182f0d0)" at line 13.
which I'll bet would confuse the vast majority of module users.

If you are going to spread Cargo Cult FUD about

my $class = ref( $proto ) || $proto;
then at least take the responsibility to tell people what you suggest they replace it with! Perhaps even keep handy a link to a discussion of both sides of the controversy.

I have my own techniques for avoiding such problems when I feel it is appropriate (usually by having my class and instance methods in different name spaces) which are way too much trouble to be the default idiom for writing OO Perl. So I advocate people follow this fine example found in the standard Perl documentation until such time as they feel the desire/need to move to more advanced techniques that can properly address class/instance method collisions without introducing such horridly confusing possibilities.

                - tye

Comment on Re^2: A few Perl OOP questions. (disparaging)
Select or Download Code
Re: Re^2: A few Perl OOP questions. (disparaging)
by Zaxo (Archbishop) on Oct 23, 2003 at 01:15 UTC

    I think the reason for disparaging that idiom has nothing to do with gifts from absent gods or monopolistic marketing practices. The reason is the idiom indicates an OO design flaw.

    The objection is one of OO principle - that class methods and instance methods should be distinct and disjoint. Instance methods deal with the state of a particular object. Class methods deal with class-wide state or instance construction.

    Your example is a common idiom only because it's one way ref($foo) || $foo methods are called. If it's necessary to intuit $one's class, why not say so by writing my $two = ref($one)->new('b');

    There is a borderline case - copy constructors. It is tempting to be able to write my $two = $one->new();
    for a deep copy of $one. Reflection on how much different that operation that is from construction with a parameter list suggests that a separate copy ctor is advisable, my $two = $one->clone();
    , an instance method. That could be written as a class method, my $two = Purified::Confusion->new($one);
    , but that would make for an unnecessarily complicated constructor.

    Tye, I thought you disliked cries of "Cargo Cult!" ;-)

    After Compline,

      Yes, I understand all of that. I don't see you say a single thing about my points. *shrug*

      I know quite well why some people don't like it. I can see their points on some levels but mostly don't see those arguments as a big deal in many cases. I can also see the (contrary) point of making life easy for the module user. Most of the time, when given a concrete example of $obj->new() being supported by a real module, I have no confusion about what is going on. In theory, it can be confusing. In practice, it often just makes good sense.

      Your node really does have the ring of FUD to me. "class methods and instance methods should be distinct and disjoint" Why? Because someone says so? Perl certainly doesn't think so -- not in the least. I don't even see you doing it. I'm sure its a nice principle with plenty of validity behind it. I even, at times, follow it more in my own OO code than I've seen done in most any other Perl OO code I've read.

      BTW, you forgot to not name your constructor "new". Also a valid (and similar) point, especially in theory, that often doesn't cause the slightest problem in so many cases of practice.

      But I'm not here to argue those things (but I threw in a bit mostly cause it was fun). Some feel that way, and I can understand their points and agree with most of them to some degree. But I just haven't seen any of the complainers bothering to notice the consequences of their banishment of this idiom.

      "Cargo Cult FUD" just had such a nice ring to it. Turnabout is fair play, don't ya know? (: (I love the "think for yourself" or "you didn't think for yourself, because what you wrote is 'cargo cult'" meta argument -- always makes me wonder what is so weak about their argument that they have to resort to it. I couldn't resist, especially the redundancy of adding "Cargo Cult" to "FUD"; it just rolls off the tongue.)

      So, yet again, the FUD mongers refuse to provide a reasonable replacement for the acursed $proto idiom.

      I find it quite rude to be told "don't do this" without any "do this instead" or even the slightest hint of what is mixed about the purported blessing.

                      - tye

        tye, the original query was about OO perl. I mentioned that the idiom gets criticised. In the followup, I explained why in terms of OO practice. Allowing object methods to set class metadata is a bad thing because it allows things which should not interact to change each other's behavior.

        I see no FUD in my statement of that: "class methods and instance methods should be distinct and disjoint". There is no fear there, and it seem a quite certain and undoubting statement. Is that what you really object to?

        What do you mean by '.. no "do this instead"'? I gave two distinct strategies for avoiding the construct.

        Are you trying to get me to suggest some new perl syntax to somehow make things alright? I won't do that. The syntax is not the issue. If you have use for ref($class) || $class, be my guest.

        BTW, why wouldn't I name a constructor new? I usually do unless I call it frobozz or clone or connect.

        Throughout this thread you've been putting words in my mouth. Please stop that.

        After Compline,

(Re)+: A few Perl OOP questions. (disparaging)
by rir (Vicar) on Oct 24, 2003 at 18:17 UTC
    I dislike the idiom because it promotes ambiguous code. The author of  $obj->new(); hides something that the author of  (ref $obj)->new(); tells you.

    Often it makes no real difference and the noise is about who is being forced to write code to accomodate someone else. I try to be more cooperative.

    Usually I would write your new more like this.

    sub new { my $class = shift( @_); croak "Bad class parameter" if not defined $class or ref $class; bless [@_], $class; }
    Which gives a message like:

    Bad class parameter at line 100

    What is it that you find fine about the idiom?

Log In?

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

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (4)
As of 2014-10-22 05:30 GMT
Find Nodes?
    Voting Booth?

    For retirement, I am banking on:

    Results (112 votes), past polls