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

Use cases for 'sub Pckg::func { }' ?

by LanX (Cardinal)
on Jul 30, 2020 at 23:08 UTC ( #11120095=perlquestion: print w/replies, xml ) Need Help??

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

It's possible to define a fully qualified sub by adding the package to the name.

So I played around with sub X::foo and noticed that sub resolution happens in the surrounding package.

That looks consistent to me, it's analogue to BEGIN{ *X::foo = sub { } } where the anonymous sub carries its package context around.

Hence calling foo() will work while bar() fails, because Data::Dump wasn't imported into X::

use strict; use warnings; use Data::Dump qw/pp dd/; sub X::foo { pp(\@_) }; BEGIN { *X::baz = sub { pp(\@_) } }; package X; sub bar { pp(\@_) } ; foo(1..3); # [1, 2, 3] baz(1..3); # [1, 2, 3] bar(4..6); # Undefined subroutine &X::pp +called

Question: What are the use cases of that pattern?

The only thing which comes to mind is monkey patching a sub in another package without adding inner helper functions into that package.

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

Replies are listed 'Best First'.
Re: Use cases for 'sub Pckg::func { }' ?
by tybalt89 (Prior) on Aug 01, 2020 at 02:44 UTC

    Do you mean something like this?

    https://rosettacode.org/wiki/Compiler/AST_interpreter#Perl

    This reads in a flattened Abstract Syntax Tree (AST) and generates from it a tree of perl objects it can then run with a simple ->run method and polymorphism.
    This does have a hash %variables that is shared between several of the subs in different packages(classes).

    There is also this, a simpler tree based expression parser and evaluator that again uses perl polymorphism to calculate a result from a tree of objects. I'm considering submitting this to https://rosettacode.org/wiki/Arithmetic_evaluation but I'm not sure if I will.

    #!/usr/bin/perl use strict; # https://rosettacode.org/wiki/Arithmetic_evaluation use warnings; sub node { bless [ splice @_, 1 ], shift } sub error { die s/\G.*//sr =~ tr/\t/ /cr, "^ $_[0] !\n" } sub want { /\G$_[1]/gc ? shift : error pop } sub expr { /\G\h+/gc; my $tree = /\G\d+/gc ? node NUMBER => $& : /\G\(/gc ? want expr(0), qr/\)/, 'Missing Right Paren' : error 'Operand Expected'; $tree = /\G\h+/gc ? $tree : $_[0] <= 0 && /\G\+/gc ? node ADD => $tree, expr(1) : $_[0] <= 0 && /\G\-/gc ? node SUBTRACT => $tree, expr(1) : $_[0] <= 1 && /\G\*/gc ? node MULTIPLY => $tree, expr(2) : $_[0] <= 1 && /\G\//gc ? node DIVIDE => $tree, expr(2) : return $tree while 1; } sub ADD::value { $_[0][0]->value + $_[0][1]->value } sub SUBTRACT::value { $_[0][0]->value - $_[0][1]->value } sub MULTIPLY::value { $_[0][0]->value * $_[0][1]->value } sub DIVIDE::value { $_[0][0]->value / $_[0][1]->value } sub NUMBER::value { $_[0][0] } sub NUMBER::show { "$_[0][0]\n" } sub UNIVERSAL::show { ref($_[0]) . "\n" . join('', map $_->show, @{$_[0]}) =~ s/^/ /g +mr } while( <DATA> ) { eval { print; my $tree = want expr(0), "\n", 'Incomplete Parse'; print $tree->show, "value of tree = ", $tree->value, "\n\n"; } or print "$@\n"; } __DATA__ (1+3)*7 42 + ( 33 + ( 7 * 8 ) 123 456 foobar 7 / foobar 7 foobar 10 - 3 - 1 10 - (3 - 1) 2 * 3 + 4 * 5 2 + 3 * 4 + 5 ((((( 7 / 4 ))))) ((((( 7 / 4 )))))))) 2 + (3 + 4 no_names_allowed ) 7 ) 1 + 3 )
      Didn't the requirement from Rosetta forbid the use of eval ?

      I'm a bit puzzled why you need all those packages, instead of defining separate methods in the same namespace.

      Tho I'm often not "skilled" enough to understand your code... ;-)

      ++ for creativity! =)

      update

      Ah, I think I got it, those packages are classes and you populate them with methods in a shorter syntax.

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

        I'm using the "block" eval, which is just a "try/catch" mechanism, so I can "die" deep in parsing recursion and still be able to go on to the next test case. It's just a different feature with the same name as the "string" eval, which is what they don't want to allow.

        I could have used a hash to map operations to their proper subs, but why bother when perl already has a hash that does that for me. "Polymorphism forever!" hehehe

        "Ah, I think I got it," - yes, yes you do :)

Re: Use cases for 'sub Pckg::func { }' ?
by jo37 (Pilgrim) on Jul 31, 2020 at 21:13 UTC

    At least you may extend a class.

    #!/usr/bin/perl use strict; use warnings; package Foo; sub new { my $class = shift; bless {@_}, $class; } package main; use Data::Dump 'pp'; sub Foo::guts { my $self = shift; pp $self; } my $foo = Foo->new(foo => 'bar'); $foo->guts;

    Greetings,
    -jo

    $gryYup$d0ylprbpriprrYpkJl2xyl~rzg??P~5lp2hyl0p$

      jo37 you are guilty of monkey patching eueueueueueueu, sirens howling, you find yourself in a Cave. It's the cellar where the King keeps his barrels of wine. To the northeast there is the red door. Below there is a trap door. Oooopppss sorry, that was the punishment for acting over a distance. Let's go again monkey-patchers. Resume... You are in the trolls cave. To the north there is the heavy rock door. Thorin enters. He is laughing...

      bw, bliako

        I find a few reasons to not oppose to this (considered evil) path:

        1. Using a module that is not maintained and nobody took over, several patches were proposed but nobody uploaded a fixed version.
          Of course you can apply the patches locally before you install it, but that is no guarantee it is also fixed on other systems.
          It is way more reliable to overrule the faulty sub or make a new one foced into the faulty package thereby making sure it works.
        2. The package owner/maint has explicitely said *not* to add the requested/required functionality (they might even have documented so), so adding the desired method by forcing it into the package is relatively safe. (problematic would only be a new maintainer who disagrees with the refusal and putting it in later anyway)
        3. When working in supporting a module that is evolving, adding methods that are not yet implemented or have been removed, all guarded by version checks is a very fine way to make your module work for the end-users regardless of the changes in the underlying module(s). I do this very regularly. (example)
        4. Overruling CORE::GLOBAL functions in test files to provide stubs.

        Enjoy, Have FUN! H.Merijn

        I confess.

        But seriously, why would I be punished for such:

        #!/usr/bin/perl use strict; use warnings; use LinkedList::Single; sub format_node_data { my ($id, $name) = @{$_[0]}; "[id:$id, name:$name]"; } sub LinkedList::Single::print { my $list = (shift)->clone; for ($list->head; $list->has_next; $list->next) { print format_node_data($list->node_data), " -> "; } print format_node_data($list->node_data), "\n"; } my $list = LinkedList::Single->new([1, 'foo'], [2, 'bar'], [3, 'baz']) +; $list->print; __DATA__ [id:1, name:foo] -> [id:2, name:bar] -> [id:3, name:baz]

        Greetings,
        -jo

        $gryYup$d0ylprbpriprrYpkJl2xyl~rzg??P~5lp2hyl0p$
Re: Use cases for 'sub Pckg::func { }' ?
by perlfan (Priest) on Jul 31, 2020 at 02:19 UTC
    Sounds like the foundations for Perl mixins. :)
Re: Use cases for 'sub Pckg::func { }' ?
by ikegami (Pope) on Jul 31, 2020 at 14:00 UTC

    What are the use cases of that pattern?

    The pattern you are observing is that the package directive controls the package in which code is compiled. sub X::foo { pp(\@_) } is simply not an exception to that. Effort to provide a special behaviour for sub X::foo { pp(\@_) } was not spent.

    Put differently,

    sub X::foo { pp(\@_) }
    is short for
    BEGIN { *X::foo = sub { pp(\@_) }; }
    which is effectively what happens every time you import a symbol from a module (e.g. use X qw( foo );).
      You effectively just repeated what I said without answering my question.

      What are the use-cases where this idiomatic construct is useful?

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

        I answered that. It's used every time you export something. e.g. use X qw( foo ); It allows foo to find other subs it should find and to use use vars vars it expects to find.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (4)
As of 2020-08-15 11:34 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Which rocket would you take to Mars?










    Results (78 votes). Check out past polls.

    Notices?