http://qs321.pair.com?node_id=52014

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

I'm trying to use a constructor to create an object and it doesn't appear to be working properly.
#main code use Send; $name="lastname"; $obj=Send->new($name); $user=$obj->{user}; $session=$obj->{session}; print "the: $user,$session"; #package Send package Send; sub new { my ($user)=@_; my $self={}; $self->{user}="$user"; $self->{session}="4556"; bless($self); return $self; } #output is below the: Send,4556
Why isn't the code outputting

the: lastname,4556.

Thanks

Replies are listed 'Best First'.
Re: perl oo
by ichimunki (Priest) on Jan 15, 2001 at 23:30 UTC

    The first argument in @_ is the package/class name. use my $class = shift; to strip that, then use bless ($self, $class); just for kicks.

    Added: just as a note, I strongly recommend reading merlyn's incredibly straightforward "perlboot" document (found in Perl 5.6+ by typing perldoc perlboot, found in every up-to-date perldoc online compendium, like this one). This is simply the shortest, sweetest intro to Perl OO that you will ever find. Even if you are not new to OO, this document will take you through examples of the classic OO usages in Perl.

Re: perl oo
by Caillte (Friar) on Jan 15, 2001 at 23:47 UTC

    Hokay... a a few things wrong here... but you were so close that its worth setting things straight.

    First, please compile your code with -w and use strict. Using -w would have shown you that perl could not find the Send.pm package. If you use use then perl searches for packages in @INC (the module path) but if you start using a package without using use perl will assume that the package is in the same file as the calling code. Of course, if it isnt then perl will generate an error.

    Removing use Send then gives a program that compiles and generates "the: Send,4556" which is almost, but not quite, what you want. The reason for this is that both of the following lines call the same function in the same way:

    $obj = Send->new($name); $obj = new Send($name);

    Both effectively break down to a call like:

    new( Send, $name ); <>Because of this we have to make a couple of changes to your new sub. First you need to read in two variables, the class and thenthe name.

     my($class, $name) = @_;

    Your bless line is wrong too, you bless an object into a class, in this case the Send class so, in this case, you would use

    bless($self, $class);

    This gives the output: "the: lastname, 4556" which is what i think you were looking for.

    <teacher_mode>There is still a lot wrong with your prorgam, even with these changes... it still will not compile if you use use strict for a start. But those two changes should set you going in the right direction</teacher_mode>

Re: perl oo
by mr.nick (Chaplain) on Jan 15, 2001 at 23:31 UTC
    Because the argument list to Send::new() is more than just what you specify on the Send->new($name). More specifically, it's the name of the class being called.

    Generally, "sub new" blocks should look like:

    sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = {}; my @args = @_; bless ($self, $class); return $self; }
      I disagree about that ref($proto) part.

      If you want an instance method called "new", I have no idea what it's doing. If you want to clone an object, call your instance method "clone" or "copy". If you want to provide a new empty object of the same class as an existing object, just use:

      my $sibling = (ref $original)->new(...);

      There is no point in putting that ref-ish crap in something called "new". In fact, it's misleading.

      Note that I'm not arguing that every method should be either a class method, or an instance method, but not both. Rather, I'm saying that "new" on an instance could mean either "clone" or "make new one like...", and thus you are confusing at least half your audience, guaranteed.

      Yes, there are other prominent members of the Perl community who disagree with me on this. Ask them if they were programming in Smalltalk in 1980. {grin}

      I consider any use of this ref($proto) || $proto in new to be "cargo cult programming", and mark it off as such in the code reviews I do.

      -- Randal L. Schwartz, Perl hacker


      update: I finally wrote this up in a way that fully explains my objections. See the last few paragraphs of my SysAdmin column, which triggered a partial rewrite of perltoot for Perl 5.8.5 removing this objectionable construct.
        Huh. I seem to have hit upon a long-standing disagreement without realizing it. Your point seems sensible; I've been doing it that way because it's the one that's in perltoot :)

Re: perl oo
by mirod (Canon) on Jan 15, 2001 at 23:33 UTC

    Your problem is when you get the arguments for new: when you do $obj=Send->new($name); the subroutine gets _2_ arguments: the class name ("Send") amd $name. so the new method should start with

    my( $class, $user)=@_;
Re: perl oo
by OeufMayo (Curate) on Jan 15, 2001 at 23:36 UTC

    From my poor knowledge on OO Perl, the first parameter of your call to 'new' is the name of the package or class.

    If you write it this way:

    sub new { my $class = @_; my $self = ( user => $_[1], session => 4556, ); bless($self, $class); return $self; }

    and it should do what you're looking for.

    <kbd>--
    PerlMonger::Paris(http => 'paris.pm.org');</kbd>
      OeufMayo: you have the right idea, but you're on the wrong track and are a bit confused about context.
      my $class = @_;
      The left side is a scalar, which means the array '@_' is being called in scalar context. As a result, $class will be set to the number of elements in @_.

      Also, you want curly braces '{}' in the "my $self =" line to create the reference to the anonymous hash. The following should work:

      sub new { my ( $class ) = @_; my $self = { user => $_[1], session => 4556, }; bless($self, $class); return $self; }
      Putting the parenthesis around $class in the first line of the sub causes it to be evaluated in list context and grabs the first element of @_. There are still better ways to write that, but I'll leave it at that for now.

      Hope this helps!

      Cheers,
      Ovid

      Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.