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

Hi monks it's my first post here. I'm usually finding solutions, but this time was not sure about what to search. So I'll just paste sample code.
#!/usr/local/bin/perl use strict; use warnings; package Test1; sub new { my $class = shift; my $self = { _txt => shift }; bless $self, $class; return $self; } sub _sub1() { #private method my $self = shift; $self->{_txt} = "bar"; return $self->{_txt}; } sub sub2() { #public method _sub1(); } sub getTxt() { my ($self) = @_; return $self->{_txt}; } 1;
When I run my project:
my $object = new Test1( "foo"); $object->sub2(); print $object->getTxt();
I get "foo" and I want to get "bar". What am I doing wrong?

Replies are listed 'Best First'.
Re: OOP method usage
by kcott (Archbishop) on Jul 07, 2012 at 09:29 UTC

    Your code in sub sub2 ... is calling _sub1() without arguments. It should probably look more like:

    my $self = shift; return $self->_sub1();

    I'll also point out that prototypes are meaningless when used with OO methods: see perlsub - Prototypes. I'd suggest changing all instances of:

    sub XXX() { ... }

    to

    sub XXX { ... }

    -- Ken

      OK, Ill fix the code
Re: OOP method usage
by Anonymous Monk on Jul 07, 2012 at 09:19 UTC

    I get "foo" and I want to get "bar". What am I doing wrong?

    You're not calling _sub1 as a method. Try  sub2 { shift()->_sub1; }

      Thank you for your reply. That works like a charm. Am I able to use $self->_sub1; in a constructor? Or is it bad programming practice ? Example:
      sub new { my $class = shift; my $self = { _txt => shift }; bless $self, $class; $self->_sub1(); return $self; }

        Yes, you can call an instance method on $self in the constructor, provided you have first called bless on it (as in your example).

        is it bad programming practice ?

        No, it’s standard practice. See perlobj:

        Once we've blessed the hash referred to by $self we can start calling methods on it. This is useful if you want to put object initialization in its own separate method:

        sub new { my $class = shift; my $self = {}; bless $self, $class; $self->_initialize(); return $self; }

        HTH, and welcome to the Monastery!

        Athanasius <°(((><contra mundum

Re: OOP method usage
by tobyink (Canon) on Jul 07, 2012 at 11:50 UTC

    As others have pointed out, the correct code for sub2 is something like this:

    sub sub2 { my ($self) = @_; $self->_sub1; }

    In this particular case, because sub2 isn't actually doing anything, other than passing straight through to _sub1, there are a couple of other options which perform better, CPU and memory wise:

    # Use goto because that automatically passes on @_ to the # next function. sub sub2 { goto \&_sub1; }

    or:

    # Just make one sub into an alias for the other... *sub2 = \&_sub1;

    There are considerations to make regarding things like inheritance though, so while each of these are faster, the first example is in many ways "better".

    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
Re: OOP method usage
by Don Coyote (Hermit) on Jul 07, 2012 at 10:31 UTC

    There are not any values being passed to _sub1() from sub2()

    by calling _sub1() using the object method you can pass the object into _sub1() and return the adapted value

    sub sub2() { #public method my $self = shift; $self->_sub1(); }
Re: OOP method usage
by Anonymous Monk on Jul 07, 2012 at 12:34 UTC
    Also notice that the customary (required?) syntax is:   Test1->new().

    The Perl implementation of objects is not quite what you might expect when coming from other languages.   But it is deceptively powerful, perhaps in part because it does not force you to do things in a certain way or make too many assumptions.

      Actually, the following are equivalent:

      my $object = MyClass->new; my $object = new MyClass;

      The second is referred to as the "indirect object syntax". It's generally discouraged because it can confuse the perl parser.

      Actually, the first syntax isn't fantastic either, because...

      package MyClass { sub new { bless []=>shift } } package OtherClass { sub new { bless []=>shift } } package main { sub MyClass () { return 'OtherClass' } my $object = MyClass->new; print ref $object; }

      Now, what does that print? You might expect $object to be an instance of MyClass, but it's actually an instance of OtherClass.

      The following are unambiguous ways to call a constructor:

      my $object = MyClass::->new; my $object = 'MyClass'->new; my $class = 'MyClass'; my $object = $class->new;

      Back to the topic of the indirect object syntax... there's a module called indirect that allows you to convert uses of indirect object syntax into fatal errors.

      perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
        So, sometimes there are cases where there you ought to pick one way to do it ... and stick with that way forever. Grab any ol' Perl package that you have respect for, look inside to see how they do it, and do it that way.