How to access a constant in Perl whose name is contained in a variable?

I have a set of constants declared in Perl:

use constant C1 => 111; use constant C2 => 222; .. use constant C9 => 999; my $which_constant = "C2"; 

How to create a Perl expression that, based on $which_constant displays a constant value with the name of this variable - for example, "222".

Please note that I cannot change any of the above conditions - this is a simplification of the real scenario: I have a module (which I do not control) from which these constants are imported. The name of one of the constants is provided by the user from the command line. I need to access the value of the corresponding constants.

I hit my head against a wall (mostly around all kinds of weird globe designs), but none of them work.

PS If the solution accesses the constants inside its own module - say My::Constants::C2 (without the need to import them), even better, but not necessary - I can easily import the correct constants into main:: using My::Constants->import($which_constant) . and yes, to top it all off, those constants are NOT exported by default, so an explicit call to import () is required.

Some of the things I tried:

  • main::$which_constant - syntax error

  • main::${which_constant} - syntax error

  • ${*$which_constant} - returns an empty value

  • *$which_constant - returns "* main :: C2"

  • ${*${*which_constant}} - empty

+4
source share
3 answers

The constant.pm defined by constant.pm are simply routines. You can use the method invocation syntax if you have a constant name in the string:

 #!/usr/bin/perl -l use strict; use warnings; use constant C1 => 111; use constant C2 => 222; print __PACKAGE__->$_ for qw( C1 C2 ); # or print main->$_ for qw( C1 C2 ); 

Thus, if you try to use a constant that is not defined, you will receive an error message.

+13
source

Perl "constants" are actually routines that return a constant value. The perl compiler can replace them with the corresponding value at compile time. However, since you want to get a value based on the search for the runtime name, you should do the following:

 &{$which_constant}(); 

(And of course, you need no strict 'refs' somewhere.)

+8
source

Sinan's suggestion to use method invocation semantics to get around strict 'refs' is the purest, easiest to read solution.

My only concern about this was that speed limits for using this approach could be a problem. We all heard about penalties for method performance and the speed advantages of built-in functions.

So, I decided to run the test (code and results follow).

The results show that regular, built-in constants work about two times faster than method calls with the literal routine name, and almost three times faster than method calls with variable routine names. The slowest approach is standard separation and calling no strict "refs"; .

But even the slowest approach works pretty fast at more than 1.4 million times per second on my system.

These tests erase my one caveat about using a method invocation method to solve this problem.

 use strict; use warnings; use Benchmark qw(cmpthese); my $class = 'MyConstant'; my $name = 'VALUE'; my $full_name = $class.'::'.$name; cmpthese( 10_000_000, { 'Normal' => \&normal_constant, 'Deref' => \&direct_deref, 'Deref_Amp' => \&direct_deref_with_amp, 'Lit_P_Lit_N' => \&method_lit_pkg_lit_name, 'Lit_P_Var_N' => \&method_lit_pkg_var_name, 'Var_P_Lit_N' => \&method_var_pkg_lit_name, 'Var_P_Var_N' => \&method_var_pkg_var_name, }); sub method_lit_pkg_lit_name { return 7 + MyConstant->VALUE; } sub method_lit_pkg_var_name { return 7 + MyConstant->$name; } sub method_var_pkg_lit_name { return 7 + $class->VALUE; } sub method_var_pkg_var_name { return 7 + $class->$name; } sub direct_deref { no strict 'refs'; return 7 + $full_name->(); } sub direct_deref_with_amp { no strict 'refs'; return 7 + &$full_name; } sub normal_constant { return 7 + MyConstant::VALUE(); } BEGIN { package MyConstant; use constant VALUE => 32; } 

And the results:

  Rate Deref_Amp Deref Var_P_Var_N Lit_P_Var_N Lit_P_Lit_N Var_P_Lit_N Normal Deref_Amp 1431639/s -- -0% -9% -10% -29% -35% -67% Deref 1438435/s 0% -- -9% -10% -28% -35% -67% Var_P_Var_N 1572574/s 10% 9% -- -1% -22% -29% -64% Lit_P_Var_N 1592103/s 11% 11% 1% -- -21% -28% -63% Lit_P_Lit_N 2006421/s 40% 39% 28% 26% -- -9% -54% Var_P_Lit_N 2214349/s 55% 54% 41% 39% 10% -- -49% Normal 4353505/s 204% 203% 177% 173% 117% 97% -- 

Results obtained using ActivePerl 826 in Windows XP, YMMV.

+4
source

Source: https://habr.com/ru/post/1300107/


All Articles