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

Perl Object Initilization

by PyrexKidd (Monk)
on Jun 09, 2011 at 17:09 UTC ( [id://908958]=perlquestion: print w/replies, xml ) Need Help??

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

Hello,
I have a feeling that this is easier than I am making it out to be, but I can't for the life of me figure out how to initialize values in an object.

Here's what works for me, but I would like to call an initialize subroutine.

#!/usr/bin/perl use strict; use warnings; package Obj; sub new { my $class = shift; my $self = { a => 20, }; bless $self, $class; return $self; } package main; my $obj = Obj->new; print $obj->{'a'};

What I would like to do is call an initialize sub, but all of the following attempts return an error: Useless use of hash element in void context at obj.pl line 19.
I'm sure this is indicative of what I have done wrong, but I don't understand how this could be void context, since I'm assigning the values to the object...

#!/usr/bin/perl use strict; use warnings; package Obj; sub new { my $class = shift; my $self = {}; bless $self, $class; $self->initialize(); #$self->initialize($self, ); #initialize($self, ); #$self = initialize($self, ); #$self = $self->initialize($self); return $self; } sub initialize { my $self = shift; $self->{ 'a' => 10 }; } package main; my $obj = Obj->new; print $obj->{'a'};

ok, so apparently the following works, but what if I have multiple values? And what if I want to pass values to the initialize routine?

#!/usr/bin/perl use strict; use warnings; package Obj; sub new { my $class = shift; my $self = {}; bless $self, $class; $self->initialize(); return $self; } sub initialize { my $self = shift; $self->{ a } = 10; return $self; } package main; my $obj = Obj->new; print $obj->{'a'};

Replies are listed 'Best First'.
Re: Perl Object Initialization
by chromatic (Archbishop) on Jun 09, 2011 at 18:04 UTC

    The easy way to do this is with Moose:

    package Obj; use Moose; has 'a', is => 'ro', default => 10; package main; my $obj = Obj->new( a => 10 );

    ... though if you must write your own initializer, the easiest and clearest and probably most efficient way is:

    sub initialize { my $self = shift; while (my ($key, $value) = splice @_, 0, 2)) { $self->{$key} = $value; } }
      Additionally, Moose offers mechanisms that can be used for object initialization (BUILD) and per attribute initialization (builder). Attributes may also be "lazy" so that they will not be initialized until they are needed (this is discussed at length in subsequent comments). Links are to the Moose documentation.
Re: Perl Object Initilization
by BrowserUk (Patriarch) on Jun 09, 2011 at 18:30 UTC

    I have to wonder why you want to make this separate from new()?

    I mean, you wouldn't want an uninitialised instance of your class floating around in the wild would you?

    And can you envisage a situation when you would re-initialise an existing instance rather than throw it away and create a new one?

    For that makes new() and initialisation a one-to-one relationship and separating them nonsensical.

    Even if the initialisation process is particularly complicated, it is far more likely that subdivisions of the initialisation--say per field initialisation and validation--will form reusable pieces of code than the initialisation process as a whole.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      I mean, you wouldn't want an uninitialised instance of your class floating around in the wild would you?

      I aim for avoiding initialization most of the time. :) I/O heavy initialization for database backed objects is best saved until absolutely needed, and possibly saved until more than one object can be initialized at the same time. How many objects get constructed and never used? Make construction cheap and it doesn't matter. Save the memory and disk and CPU for the stuff you really need to use.

      I have a rule now for my code...save all work until it's proven to be necessary. Don't initialize an object until a method is called on that object that requires it to be initialized. Extending that, use require-on-demand instead of 'use'. Don't even compile dependency modules until a caller wants an object of their type constructed. autouse packages when trying to get legacy code to perform (just refactor out those pesky imports and that indirect object syntax ... your maintainers don't really want either of those anyway). Use Abstract Factory with a require-on-demand design for new code. Design for modular run-time, not just modular maintain-time.

      As long as objects can identify themselves uniquely and know whether they've been initialized or not, then the rest is no big deal. No need for fully initialized objects at all times.

      --Dave

        Hm. I cannot see the point in instantiating an object that will never be used. Better to leave the variable as undef until it is needed and then initialise it.

        To my way of thinking, instantiating uninitialised objects is as short sighted as declaring variables in C without initialising them.

        And auto-initialising on demand sounds even worse. Maybe I'd just need to see a real-world example of use to convince me otherwise, but I am sceptical.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Perl Object Initilization
by Perlbotics (Archbishop) on Jun 09, 2011 at 17:43 UTC

    If I understand your question correct, than this should work:

    sub initialize_with_pars { my $self = shift; # Alternative 1: a,b can be overwritten by AVPs given in @_ %{$self} = (%{$self}, 'a' => 10 , 'b' => 20, @_); # Alternative 2: init. of a,b has priority over AVPs from @_ # %{$self} = (%{$self}, @_, 'a' => 10 , 'b' => 20); } ... # Usage: $self->initialize_with_pars; # or $self->initialize_with_pars( 'c' => 30 );

Re: Perl Object Initilization
by rev_1318 (Chaplain) on Jun 09, 2011 at 17:44 UTC
    Something like:
    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; package Test; sub new { my ($class, @args) = @_; my $self = {}; bless $self, $class; $self->init(@args); return $self; } sub init { my ($self, @args) = @_; %$self = ( a => 10, b => 20, @args, ); return $self; } package main; my $test1 = Test->new(); print "$test1->{a}\n"; my $test2 = Test->new(a => 40); print "$test2->{a}\n";
    init sets defaults, which you can override with your values...

    Paul

Re: Perl Object Initilization
by PyrexKidd (Monk) on Jun 09, 2011 at 19:34 UTC

    Ah, HA! So I have to dereference $self to a hash then I can treat it as a hash. (DUH! right...)

    I've always heard that it is bad practice to access an objects 'private' variables. I know this concept isn't enforced explicitly in Perl, but is there a good way to do this?

    #!/usr/bin/perl use strict; use warnings; use Data::Dumper; package Obj; sub new { my ($class, @args) = @_; my $self = {}; bless $self, $class; $self->init(@args); return $self; } sub init { my ($self, @args) = @_; %{$self} = ( a => 10, @args, ); return $self; } sub print_val_a { my $self = shift; # my $FHOUT = shift || "STDOUT"; # print $FHOUT $self->{'a'} . "\n"; print $self->{'a'} . "\n"; } package main; my $obj1 = Obj->new(); $obj1->print_val_a(); my $obj2 = Obj->new(a => 40); $obj2->print_val_a();

    (Granted for some reason this: # my $FHOUT = shift || "STDOUT"; # print $FHOUT $self->{'a'} . "\n"; doesn't work as expected ...)

    this works but then how do you control output direction? Is there a 'cleaner' way to do this?

    and finally, how about destroying objects? according to perlobj, objects are destroyed automagically when they go out of scop, but what if I want to destroy them manually? as far as I can tell, calling a method DESTROY does not automatically destroy it... Is there even any reason to cleanup after your objects?

      you should not redefine $self once you have blessed it into objecthood. Assign to individual keys of the underlying hash instead. In addition to the method given by chromatic above, you can also do it this way (just a slightly different style):
      sub init { my $self = shift; my %args = @_; while (my ($attribute, $value) = each %args){ $self->{$attribute} = $value; } }
      Here yuo are using the fact that an even-sized list can simply be assigned to a new hash to populate it ( which is what you always do when you say my %hash=( key1 => value2 ) as '=>' is just a glorified comma).
      I would also agree that, particularly in this case, a separate init method is not needed, because you are just assigning values to attributes and that can all be done when you construct the hash that you then bless in the 'new' method.
      There may be some cases where more complicated setup needs to be done that might be better off in separate subs, such as connections to various databases, but then I would call them things like '_init_db_connection' or whatever you need to do.
      I would also second chromatic's suggestion to look into Moose soon. If you are just starting with OO programming in Perl then it's certainly good to see the non-Moose, old style first and understand it but then move on to a more modern object system like Moose. It seems like a bit of a learning curve at the beginning but it's well worth it.
        If you are just starting with OO programming in Perl then it's certainly good to see the non-Moose, old style first and understand it but then move on to a more modern object system like Moose.

        I think that's backwards, especially if you've not done OO before. Perl 5's default OO system exposes so much plumbing it's easy to get lost in the syntactic details of how to do things instead of understanding well what to do and why to do it.

        That's kind of like suggesting that you make your own pie crust by hand before you can ever put toppings on a bake at home pizza.

        This is a simplified version.

        In this particular case, you are saying that it is better to pass a hash (or hash ref) and build any attributes/values (using a loop) because if you have an uneven list it will cause a mismatch of keys/values?

        on the note of 'initialize as needed', would you define the respective initialization subroutines in the class definition, then call them from the code where you require the object?

      1) # my $FHOUT = shift || "STDOUT";

      Granted for some reason this: # my $FHOUT = shift || "STDOUT"; # print $FHOUT $self->{'a'} . "\n"; doesn't work as expected ...)

      "STDOUT" and "GOBBLEDYGOOK" are essentially equivalent: they are both strings--not filehandles.

      2)...and finally, how about destroying objects? according to perlobj, objects are destroyed automagically when they go out of scop, but what if I want to destroy them manually? as far as I can tell, calling a method DESTROY does not automatically destroy it... Is there even any reason to cleanup after your objects?

      There can be. If you have file handles or database connections you want to close. Or if you merely want to know when your objects are destroyed, you can print out a message. There are also more advanced reasons for calling DESTROY:

      see here

      perl calls DESTROY for you--just before perl is going to destroy the object. If you don't have a specific reason for defining a DESTROY method, then don't. perl will usually take care of everything for you.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://908958]
Approved by Corion
Front-paged by MidLifeXis
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (5)
As of 2024-03-29 10:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found