http://www.perlmonks.org?node_id=300475

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hello to everybody.

I wanted to know if anyone here could help me with a few perl oop questions?

I do not fully understand the following code fragments:

my $class = ref( $type ) || $type; $self->{ hireDay }->setDate( @_ ); my $self = $class->SUPER::new();

These originate from different programs but in order for me to understand the entire code, I need to know what these are doing.

Thank you,
Ciao, Alexis

Replies are listed 'Best First'.
Re: A few Perl OOP questions.
by Zaxo (Archbishop) on Oct 20, 2003 at 05:25 UTC
    my $class = ref( $type ) || $type;

    That sets $class to the string returned from ref. If that return is false ($type is not a reference), $class is set to the value of $type. That code is used to intuit a class name from an instance of the class, so a class method many be called as if it were an instance method. That is an idiom which is disparaged these days as too admissive of bugs.

    $self->{ hireDay }->setDate( @_ );

    $self is a reference to a hash. Its 'hireDay' key contains an object with an instance method called setDate. That method is called with the current argument array.

    my $self = $class->SUPER::new(); $self is make to be an instance of the first parent class having a new() class method. It$self will likely soon be re-blessed into $class, perhaps with some additional initialization.

    After Compline,
    Zaxo

      $self is make to be an instance of the first parent class having a new() class method. It$self will likely soon be re-blessed into $class, perhaps with some additional initialization.

      I don't think this is correct. Try the following:

      package Foo; sub new { my $class = shift; print "In Foo with '$class'\n"; return bless {}, $class; } package Bar; @ISA = qw(Foo); sub new { my $class = shift; my $self = $class->SUPER::new; print "In Bar with a self of '$self'\n"; return $self; }

      Now, I'm assuming that all classes in this hierarchy are using the two-arg form of bless. If they are, then $class will be passed around and it will be the child class.

      ------
      We are the carpenters and bricklayers of the Information Age.

      The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

      ... strings and arrays will suffice. As they are easily available as native data types in any sane language, ... - blokhead, speaking on evolutionary algorithms

      Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

        You're right. The delegated call still gets the child's class name as its first argument. Further initialization remains likely.

        After Compline,
        Zaxo

      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;
      and
      #!/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 confusion.pl 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

        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,
        Zaxo

        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 file.pl line 100

        What is it that you find fine about the idiom?