It's possible to print a variable's name by *var{NAME}
, is it possible to print the argument's name in a subroutine?
Below is what I want to achieve
var_name($myVar); will print myVar
sub var_name{
print *_{NAME}; # Prints `_`, but want `myVar`
}
CodePudding user response:
First, your attempt using print *_{name};
does work; but it prints the name associated with the typeglob of _
(The one for things like $_
and @_
), which isn't what you want. If you pass a typeglob/reference to typeglob to the function you can extract its name by de-referencing the argument:
#!/usr/bin/env perl
use warnings;
use strict;
use feature qw/say/;
# The prototype isn't strictly necessary but it makes it harder
# to pass a non-typeglob value.
sub var_name :prototype(\*) {
say *{$_[0]}{NAME}; # Note the typeglob deref
}
my $myVar = 1;
say *myVar{NAME}; # myVar
var_name *myVar; # myVar
CodePudding user response:
You get _
because the NAME
associated with *_
is _
.
So what glob should you use? Well, the glob that contains the variable used as an argument (if any) isn't passed to the sub, so you're out of luck.
A glob-based solution would never work with my
variables anyway since these aren't found in globs. This means the very concept of a glob-based varname
couldn't possibly work in practice.
Getting the name of the variables would entail examining the opcode tree before the call site. I believe this is how operators achieve this in situations such as the following:
$ perl -we'my $y; my $x = 0 $y;'
Use of uninitialized value $y in addition ( ) at -e line 1.
$ perl -MO=Concise -we'my $y; my $x = 0 $y;'
a <@> leave[1 ref] vKP/REFC ->(end)
1 <0> enter v ->2
2 <;> nextstate(main 1 -e:1) v:{ ->3
3 <0> padsv[$y:1,3] vM/LVINTRO ->4
4 <;> nextstate(main 2 -e:1) v:{ ->5
9 <2> sassign vKS/2 ->a
7 <2> add[t3] sK/2 ->8 <-- This is what's issuing
5 <$> const[IV 0] s ->6 the warning.
6 <0> padsv[$y:1,3] s ->7 <-- This is the source of
8 <0> padsv[$x:2,3] sRM*/LVINTRO ->9 the name in the warning.
-e syntax OK