in reply to Re: Calling module function from within a blessed module
in thread Calling module function from within a blessed module

$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.

Replies are listed 'Best First'.
Re^3: Calling module function from within a blessed module
by shmem (Chancellor) on Jan 02, 2021 at 16:51 UTC
    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'
Re^3: Calling module function from within a blessed module
by Bod (Parson) on Jan 02, 2021 at 16:42 UTC
    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!

      "... anyone who names their package "0" is going to asking for trouble!"

      Naming a package 0 is a fatal, compilation error:

      $ perl -e 'package X;' $ perl -e 'package 0;' syntax error at -e line 1, near "package 0;" Execution of -e aborted due to compilation errors.

      The problem is likely to occur where, in some code completely separate from yours, someone writes '$x->your_method()' when, perhaps, '$y->your_method()' was intended.

      I had some difficulty coming up with an example. Here's some valid, albeit highly contrived, code to demonstrate the concept.

      I've used a common alias of mine to show code validity:

      $ alias perle alias perle='perl -Mstrict -Mwarnings -Mautodie=:all -MCarp::Always -E +'
      $ perle ' package X { use Scalar::Util "blessed"; sub new { bless {}, __PACKAGE__; } sub meth1 { say "meth1: [", ref $_[0], "]" } sub meth2 { say "meth2: [", blessed $_[0] // "undef", "]" } sub meth3 { say "meth3: [", defined blessed $_[0], "]" } }; package main; my $x = 0; my $y = X::->new(); $x->X::meth1(); $x->X::meth2(); $x->X::meth3(); $y->X::meth1(); $y->X::meth2(); $y->X::meth3(); ' meth1: [] meth2: [undef] meth3: [] meth1: [X] meth2: [X] meth3: [1]

      The 'package X;' is intended to represent your code; the 'package main;' (although quite superfluous here) is intended to represent "some code completely separate from yours".

      — Ken

        Naming a package 0 is a fatal, compilation error ... The problem is likely to occur where, in some code completely separate from yours, someone writes '$x->your_method()' when, perhaps, '$y->your_method()' was intended.

        Another example might be auto-generated package names (though if such code generated a package named "0", one could question the sanity of that choice...)

        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 blessed($_[0]) && $_[0]->isa(__PACKAGE__); dd 'foo', $self, \@_; } sub bar { my $self = shift if defined blessed($_[0]) && $_[0]->isa(__PACKAGE__); dd 'bar', $self, \@_; } } { no strict 'refs'; @{"0::ISA"} = ('Foo') } my $x = bless {}, '0'; $x->foo(); # ("foo", undef, ["0=HASH(0x561239194f3e)"]) $x->bar(); # ("bar", "0=HASH(0x561239194f3e)", [])

        Heh...

        perl -E ' $o = bless \$o, 0; *{"0::barf"} = sub {say "woof $_[1]"}; $foo = 0; $foo->barf("warf"); say $o; $o->barf("chrrr, wuff!"); 0->barf("what?")' woof warf 0=REF(0x1267880) woof chrrr, wuff! woof what?

        This is part of perl's flexibility I dearly love, and that shouldn't go away. I could - if there was a need for it! - even make integers into packages and let them have their own methods. Although those integers are strings as package names, perls builtin conversions just dwim.

        perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
        I didn't read the thread and can't comment on the discussion and motivation, but this caught my eye:

        > Naming a package 0 is a fatal, compilation error:

        Yeah but like many things in Perl this can be fabricated.

        Packages are just entries with trailing :: in main's STASH.

        And its possible to alias STASH entries via type globs.

        So create a temporary package, alias it to "0::" and delete the temp package.

        Mission accomplished! :)

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        Wikisyntax for the Monastery

        PS: Please don't crucify me now ... I haven't met my Maria Magdalena yet!