Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does direct binding of an `our &foo` not work, but indirecting via a dynamic lookup does?

Why is there a difference between r1 and r2 when called outside of module TEST?

module TEST {
    our &r1 := OUR::{'&r1'} := sub {
        say 'routine 1'
    }

    r1();            # routine 1

    our &r2 := sub {
        say 'routine 2'
    }

    r2();            # routine 2
}

import TEST;

say TEST::.keys;     # (&r1 &r2)

TEST::r1();          # routine 1
TEST::r2();          # Cannot invoke this object (REPR: Uninstantiable; Callable) ...

There is an error when trying to run subroutine r2 outside of module TEST where it was defined.

like image 224
jakar Avatar asked Jun 06 '20 18:06

jakar


1 Answers

TL;DR Binding to an our is pointless. Binding to an OUR::<&foo> is effective. I like naming things... It seems you've invented a technique which I hereby dub "@jakar's double bind our".

Why the direct binding only works inside the module

In a comment on his answer to an earlier SO jnthn concludes that we could perhaps have an error message, or perhaps a warning, to the effect that:

binding to an our variable is pointless use of our.

(What he means is that the binding only works inside the module, not outside, as you have discovered.)

There's an old and still open issue Binding a variable at BEGIN time doesn't stick around for runtime that discusses the general problem in depth.

Why the dynamic lookup works outside the module

From Symbols that start with core namespaces always get exported, jnthn notes that:

stashes are always open to poke symbols in to.

So, ignoring use of symbols inside your module, your code is doing this:

module TEST {
    OUR::{'&r1'} := sub { say 'routine 1' }
    our &r2;
}

import TEST;

TEST::r1();          # routine 1
TEST::r2();          # Cannot invoke this object (REPR: Uninstantiable; Callable) ...

@jakar's double bind our

If one wants to be able to declare a symbol and use it both inside and outside the module and insists on using binding then your trick of declaring it with a double bind may be the best technique available:

    our &r1 := OUR::{'&r1'} := sub { ... }
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^ works *outside* module
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ works *inside* module

Some things I'm curious about:

  • Have you been able to confirm any significant specific and practical advantage(s) that can be accrued from binding instead of assigning an our?

  • Do folk want to get around the "binding to an our variable is pointless" issue? If so, would they be happy to use @jakar's double bind our?

  • Does your technique apply to all sigils? (I would expect so but will leave it to you to explore such aspects. :))

like image 80
raiph Avatar answered Nov 15 '22 07:11

raiph