http://qs321.pair.com?node_id=1174356


in reply to How relevant is the order of 'use's ?

It seems to come from the way constant works.

use Data::Dump qw/pp/; use constant { C1 => 10 }; sub C2 { 20 } say pp $::{C1}; say pp $::{C2}; __DATA__ \10 *main::C2
So constants aren't actually just functions that are added to the symbols table, because instead of a glob there is a reference to the value.

The problem with your code is that your import function replaces the whole entry in the symbols table (everything in $::{SUCCESS} is replaced by $Demo2::{SUCCESS}), instead of just the CODE section of the glob. Somehow it seems that constant makes the reference to the constant's value and the glob coexist, but when you remove the glob manually from the symbols table, perl can't find the symbol SUCCESS anymore.

Funny thing is, if you just remove the line that prints the value of the constant SUCCESS, $SUCCESS gets printed, but with the constant's value. So with : use constant { SUCCESS => 5 }; in Demo2, the line print "\$SUCCESS: $SUCCESS\n"; prints "SUCCESS: 5".

Something like $main::{SUCCESS} = $Demo2::{SUCCESS}->*{CODE} (under use feature 'postderef') may work better. (Edit: no it doesn't, since $Demo2::{SUCCESS} is a ref to a scalar, not a glob...)

Replies are listed 'Best First'.
Re^2: How relevant is the order of 'use's ?
by Anonymous Monk on Oct 20, 2016 at 14:21 UTC

    That's not exactly what constant does, it does this:

    use Data::Dump qw/pp/; use constant { C1 => 10 }; sub C2 () { 20 } say pp $::{C1}; say pp $::{C2}; __END__ \10 \20

    The empty prototype allows for inlining. See Constant Functions.

      Oh right, I forgot the prototype! Thanks :).

Re^2: How relevant is the order of 'use's ?
by Krambambuli (Curate) on Oct 20, 2016 at 13:58 UTC
    yesss.... Your response, as well the previous one, gave the right direction.

    The defined import function is *not* OK. Replacing it with something closer to what Exporter does seems to solve the problem:
    package Demo2; sub import { #${[caller]->[0].'::'}{$_} = ${__PACKAGE__."::"}{$_} *{[caller]->[0].'::'.$_} = \&{__PACKAGE__."::$_"} foreach grep { not /^(ISA|isa|BEGIN|import|Dumper)$/ } keys %{__PACKAGE__."::"}; } use constant { SUCCESS => 0, }; 1;
    Now I just have to understand how come that it works :)

      Actually I think you can do even simpler/easier to read:

      use Exporter; use base qw/Exporter/; our %constants; BEGIN { push @ISA, 'EXPORTER'; %constants = (SUCCESS => 1); @EXPORT = map "&$_", keys %constants; } use constant \%constants;
      Since I guess your goal is to export all the constants in Demo2 without having to provide the list of names twice. And with the & appended to each name, there's no risk of overwriting $SUCCESS;