Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Calling module function from within a blessed module

by Bod (Parson)
on Jan 02, 2021 at 15:31 UTC ( [id://11126140]=perlquestion: print w/replies, xml ) Need Help??

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

I'm looking for the 'right' way to call a function from within the module when that module is usually blessed. I've been putting an empty string as the first parameter passed to the function but I feel sure there is a nicer way to do this.

package Some::Module; use strict; sub new { return bless {}; } sub do_something { my ($self, $param) = @_; # ...do something... return $param; } sub do_more { my $self = shift; return do_something('example'); }

If we create an instance of this then call the function

my $instance = Some::Module->new; $instance->do_something('testing');
a reference to $instance is passed to $self in the function (I think) and 'testing' is passed to $param.

But when the same function is called from within the module by do_more();, there isn't a reference to anything to be passed to do_something as the first argument so the argument list is out. Do we just add a dummy argument to the call within do_more like this

sub do_more { my $self = shift; return do_something('', 'example'); }
or is there a more elegant solution?

Replies are listed 'Best First'.
Re: Calling module function from within a blessed module
by 1nickt (Canon) on Jan 02, 2021 at 15:39 UTC

    Hi,

    Since this is an object class:

    sub do_more { my $self = shift; return $self->do_something('example'); }

    Hope this helps!


    The way forward always starts with a minimal test.
      Hope this helps!

      That helps tremendously thank you.
      The 'nicer' way is obvious after it has been demonstrated.

Re: Calling module function from within a blessed module
by haukex (Archbishop) on Jan 02, 2021 at 15:40 UTC

    Since both do_something and do_more appear to be methods, since they both take $self as their first argument, then you probably should always call them as such.

    sub do_more { my $self = shift; return $self->do_something('example'); }

      I somehow knew there would be a 'nice' way of doing this...
      Obvious when it's pointed out!

      Thank you

Re: Calling module function from within a blessed module
by stevieb (Canon) on Jan 02, 2021 at 17:01 UTC

    Another way if you want to keep it a function, which will prevent it from being accessible outside of your class, or if you want to export it as a function if your module also provides non-OO functionality:

    package Foo; use warnings; use strict; use Exporter qw(import); our @EXPORT_OK = qw(function_or_method); our %EXPORT_TAGS = (all => [@EXPORT_OK]); sub new { return bless {}, shift; } sub function_or_method { # Throw away the first param if: # A) it's defined, and # B) it's either the class, or an object of the class if (defined $_[0]) { shift if $_[0] eq __PACKAGE__ || ref $_[0] eq __PACKAGE__; } # Now we grab the remaining params (if expecting any) my ($call_num, $call_type) = @_; print "Num: $call_num called as $call_type\n"; }

    The calling script:

    use warnings; use strict; use lib '.'; use Foo qw(:all); # Call as function function_or_method('1', 'function'); # Call as method my $obj = Foo->new; $obj->function_or_method('2', 'method');

    Note that if you shift off the object to use the symbol as a function only, you obviously can't retrieve any of the object's attributes or call its other methods unless 1) you have stored a saved object globally (ie. at the class scope) or 2) you pass in an object through explicit parameter passing.

    Sometimes I provide my users the option of an OO interface or functional interface for an entire class. Again, if used in non-OO context, you can't call things on $self within the module. My entire WiringPi::API (source) is one such distribution that is 100% OO capable, and 100% functional capable.

      This (nice post++ btw) combined with butthole-politics brings me to think about verification of an object. Is that subject an object of our class?

      Hmm... is this really an Irishman (or insert $country instead) and not some offspring of Letonian, given that there was a wave of immigration from there to Ireland? and he claims to be irish because offsprings of his ancestors moved to Ireland?

      Depending on that, what methods are available? etc. Maybe I'll be coding something like Acme::Object::Racist or such :-D

      perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
Re: Calling module function from within a blessed module
by shmem (Chancellor) on Jan 02, 2021 at 15:53 UTC

    This looks like you want do_soemthing() to act both as a method and a function.
    If so, you need to check the first argument passed in. Inside that sub you would decide what to do either way.

    sub do_something { my ($self, $param); $self = shift if ref $_[0] eq __PACKAGE__; # first argument is obj +ect $param = shift; # ...do something... if ($self) { # method ... } else { # function ... } return $param; }

    If it is a mere function internal to the class, it is good practice to prepend the function name with a dash. That's an informal convention to mark functions private to the module or class.

    If it is strictly a method, then the answers of my fellow monks apply: $self->method(@args)

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
      $self = shift if ref $_[0] eq __PACKAGE__;

      Note that this unfortunately breaks for subclasses. Personally I prefer Scalar::Util's blessed and UNIVERSAL's isa.

      use warnings; use strict; { package Foo; use Data::Dump; use Scalar::Util qw/blessed/; sub new { return bless {}, shift } sub foo { my $self = shift if ref $_[0] eq __PACKAGE__; dd 'foo', $self, \@_; } sub bar { my $self = shift if defined blessed($_[0]) && $_[0]->isa(__PACKAGE__); dd 'bar', $self, \@_; } } { package Bar; use parent -norequire, 'Foo'; } Foo::foo('a'); # ("foo", undef, ["a"]) Foo::bar('b'); # ("bar", undef, ["b"]) my $f = Foo->new(); $f->foo('c'); # ("foo", bless({}, "Foo"), ["c"]) $f->bar('d'); # ("bar", bless({}, "Foo"), ["d"]) my $g = Bar->new(); $g->foo('e'); # ("foo", undef, [bless({}, "Bar"), "e"]) - oops! $g->bar('f'); # ("bar", bless({}, "Bar"), ["f"])

      Update: Added arguments to calls to make @_ more clear. Update 2: I guess in case the package name is "0", one could be doing defined blessed instead of just plain blessed, so I've updated the above, but since that's pretty unlikely, I'd say it's optional.

        Note that this unfortunately breaks for subclasses.

        This is true. Thanks for pointing that out, so I don't have to do that ;)

        The OP was really about calling syntax, and I sneaked in dual subs (method/function) and the __PACKAGE__ keyword, just to have that mentioned. Now you bring on subclassing, which is great - and a big field to tackle. Yes, the check for __PACKAGE__ is suitable for classes which aren't meant to be subclassed, won't be, or "I don't care about" modules, and more so: which strictly forbid subclassing.

        Your post is right, mine wasn't wrong, and from here we can go on exploring the whole perl OO fractal landscape... ;)

        perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
        I guess in case the package name is "0"

        Much as it is good to consider edge cases, anyone who names their package "0" is going to asking for trouble!

Re: Calling module function from within a blessed module
by tobyink (Canon) on Jan 03, 2021 at 11:48 UTC

    You are using the one argument version of bless.

    sub new { return bless {}; }

    Never, ever, ever do this. The one argument version of bless really should issue a warning.

    Do this:

    sub new { my $class = shift; return bless( {}, $class ); }
      Never, ever, ever do this. The one argument version of bless really should issue a warning.

      Actually, in real code I do not generally use the one argument version. I created that as a minimal example to support the question.

      Having said that, I don't know why I avoid the single argument version. It is because I have copied other code that works and looks like the author knows what they are doing which is not exactly the most rigorous methodology for learning...

        The reason why you generally shouldn't use the one-argument version of bless is because it makes subclassing more difficult.

        If you have two classes, Parent and Child, and Parent uses bless {}, $_[0];, then Child can simply inherit Parent's new (or other constructor) and Child->new() will Just WorkTM.

        If Parent uses one-argument bless, then it will always create a Parent object, and Child will have to override the constructor (either writing a completely new constructor, or calling Parent's constructor and re-blessing the result before returning it).

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (4)
As of 2024-04-18 20:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found