I'm making a package, where I have to get a symbol's value by its name in a sub, while the symbol is defined outside the sub.
Here is the simplified code, it works as expected:
#! /usr/bin/env perl6
sub dump_value($symbol) {
say ::("$symbol")
}
# usage:
my $x = 10;
dump_value('$x');
# expected output: 10
# actual output: 10
Then I put the 'dump_value' in a standalone file as below:
# somelib.pm6
unit module somelib;
sub dump_value($symbol) is export {
say ::("$symbol")
}
# client.pl6
#! /usr/bin/env perl6
use lib ".";
use somelib;
my $x = 10;
dump_value('$x');
The compiler complained:
No such symbol '$x'
in sub dump_value at xxx/somelib.pm6 (somelib) line 3
in block <unit> at ./client.pl6 line 8
Following are some experiments. None of them succeeded.
say ::("MY::$symbol")
say ::("OUR::$symbol")
say ::("OUTER::$symbol")
say ::("CLIENT::$symbol")
...
So how to fix the code?
UPDATE:
Thank you! CALLERS::($symbol)
solved my original problem. But in a bit more complex situation, the complier complained again:
# somelib.pm6
unit module somelib;
sub dump_value(@symbols) is export {
# output: 6
say CALLERS::('$x');
# error: No such symbol 'CALLERS::$x'
say @symbols.map({ CALLERS::($^id) } )
}
# client.pl6
#! /usr/bin/env perl6
use lib ".";
use somelib;
my $x = 6;
my $y = 8;
dump_value(<$x $y>);
UPDATE AGAIN:
use OUTER::CALLERS::($^id)
.
UPDATE AGAIN AND AGAIN:
After I put the 'dump_value' in another sub, it didn't work any more!
# somelib.pm6
unit module somelib;
sub dump_value(@symbols) is export {
say @symbols.map({ OUTER::CALLERS::($^id) } )
}
sub wrapped_dump_value(@symbols) is export {
dump_value(@symbols)
}
#! /usr/bin/env perl6
use lib ".";
use somelib;
my $x = 6;
my $y = 8;
# ouput: (6 8)
dump_value(<$x $y>);
# error: No such symbol 'OUTER::CALLERS::$x'
wrapped_dump_value(<$x $y>);
According to the documentation:
An initial :: doesn't imply global. Here as part of the interpolation syntax it doesn't even imply package. After the interpolation of the ::() component, the indirect name is looked up exactly as if it had been there in the original source code, with priority given first to leading pseudo-package names, then to names in the lexical scope (searching scopes outwards, ending at CORE).
So when you write say ::("$symbol")
in dump_value()
in the somelib
package, it will first lookup $symbol
in the current scope, which has value '$x'
then try to look up $x
(also in the current scope), but the variable $x
is defined in the caller's lexical scope, so you get the No such symbol '$x'
error.
You can refer to the caller's lexical symbol given by the value of $symbol
using either:
CALLER::MY::($symbol); # lexical symbols from the immediate caller's lexical scope
or
CALLERS::($symbol); # Dynamic symbols in any caller's lexical scope
see the package documentation page.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With