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

Hey monks,

this is an apparently easy to answer question, but I have not found an answer with a quick search over perlmonks.
All I want to do is to call a method of a class within the constructor of the class. But at this point it isn't blessed yet. So how do I handle this best without calling the method explicit after creating the object?
Any clues welcome! Thanks in advance.

package Disk; use strict; # constructor sub new { my $class = shift; my $device = shift; my $self = { 'device' => $device, 'info' => setInformation($device), # this is the method i want to +be called }; bless $self, $class; } sub setInformation { my $self = shift; my $device = shift; my $model = qx(hdparm -i $device | grep -i model); $self->{'info'} = $model =~ /.*model=(.+?),.*/i; } sub getInformation { my $self = shift; return $self->{'info'}; }

tennis players have fuzzy balls.

Replies are listed 'Best First'.
Re: calling a method within a constructor
by dirving (Friar) on Apr 11, 2007 at 08:29 UTC
    Try something like this:
    sub new { my $class = shift; my $device = shift; my $self = { 'device' => $device, }; bless $self, $class; $self->setInformation($device); return $self; }

    There's nothing particularly magical about bless -- you can call it in the middle of the constructor with no ill effects, as long as you remember to explicitly return the object you created.

    -- David Irving
      Thank you, this works fine for me! (It isn't that nifty because you have to watch the order (what is seemingly a peculiarity of perl), but hey, it works!)

      tennis players have fuzzy balls.

        It's a peculiarity only if you want Perl to behave as other OO languages.

        OOP, if you listen to the purists, is about taking some data and some behavior and associating the two of them such that you can call behaviors on the data. That most OO language designers think programmers are too stupid to be entrusted with the mechanics of this isn't Perl's problem.

        As for constructors, there's nothing magical about new() at all. DBI uses connect() as the constructor - there is no new().


        My criteria for good software:
        1. Does it work?
        2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: calling a method within a constructor
by tirwhan (Abbot) on Apr 11, 2007 at 08:42 UTC

    I'd change the setInformation subroutine to

    sub setInformation { my $self = shift; my $device = shift || $self->{device}; $self->{info} = _setInformation($device); } sub _setInformation { my $device = shift; my $model = `hdparm -i $device`; return $model =~ /model=([^,]+)/i; }

    And the constructor to

    sub new { my $class = shift; my $device = shift; my $self = { 'device' => $device, 'info' => _setInformation($device), }; bless $self, $class; }

    This way, you're calling _setInformation as a normal subroutine, without having to use the (as yet uninstantiated) Disk object. By preceding the subroutine name with an underscore you're also indicating that this subroutine is for private use of your module alone and should not be called by outside code (this is a common convention in Perl modules). You might also want to call that subroutine something different to make differentiation with the method easier (e.g. _setInformationInternal or something) but that's purely an aethetic decision. The setInformation method remains for outside code to call after the Disk object has been instantiated with Disk->new() (if you don't think this is necessary you can leave the method out entirely).

    One of the beauties of OO programming in Perl is that the language doesn't force you into the OO paradigm the entire time and allows for sensible little shortcuts like the above. If this doesn't appeal to you you could always just call your original setInformation method after blessing $self. There's nothing that forces you to return from the constructor immediately after blessing after all.

    I also slightly changed the way you were parsing the hdparm output. Since you need a regex to obtain the model specification anyway I don't see the point of calling grep via the shell. And the regex I use is slightly more clear. IMO. YMMV.


    All dogma is stupid.
      Thank you for your view and time on that. I live, I learn :)

      tennis players have fuzzy balls.