Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Why doesn't the code below print "mybase"?
#!/usr/bin/perl -w use strict; my $Base = 'mybase'; use constant BASE => $Base; print "BASE: ", BASE, "\n";
Result:
# perl test.pl + Use of uninitialized value in print at test.pl line 6. BASE:

Replies are listed 'Best First'.
Re: Using constants. What am I doing wrong?
by kvale (Monsignor) on Feb 22, 2005 at 04:01 UTC
    As with all "use" directives, defining a constant happens at compile time, before the code is run. At compile time, $Base has no value. That is why this works:
    #!/usr/bin/perl -w use strict; use constant BASE => 'mybase'; print "BASE: ", BASE, "\n";
    and your code does not.

    Update: If you want to set a 'symbolic constant' to a variable, you could use a variable and stick to the convetion that all caps means constant:

    !/usr/bin/perl -w use strict; my $BASE = 'mybase'; print "BASE: $BASE\n";
    This also has the advantage of allowing variable interpolation.

    -Mark

Re: Using constants. What am I doing wrong?
by dws (Chancellor) on Feb 22, 2005 at 04:05 UTC

    Why doesn't the code below print "mybase"?

    In Perl, execution of a script doesn't necessarily happen top-to-bottom. Certain constructs, notably

    BEGIN { }
    blocks, are executed as they are encountered. The use keyword is also processed when encountered, so that definitions it pulls in are available as the rest of the script is compiling. In your script, this means that
    use constant BASE => $Base;
    is being executed before $Base has been assigned a value. Since the purpose of the constant module is to establish constants, simply rewriting that line to
    use constant BASE => 'mybase';
    is sufficient.

Re: Using constants. What am I doing wrong?
by saskaqueer (Friar) on Feb 22, 2005 at 04:50 UTC

    Others have told you why you get the result you get; here's a couple of ways to get around it:

    # this: BEGIN { use vars '$Base'; $Base = 'mybase'; } use constant BASE => $Base; # or this: my $Base = 'mybase'; sub BASE () { $Base }
      The correct solution you're looking for is:
      my $Base; BEGIN { $Base = 'mybase' } use constant BASE => $Base;

      Being right, does not endow the right to be rude; politeness costs nothing.
      Being unknowing, is not the same as being stupid.
      Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
      Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

        Strange. I could have sworn I'd tried that solution first, but found it to not work. Just tried it again before I was going to post saying 'that does not work', but all of a sudden it works. Strange world :)

      The second one does not make a constant

      perl -le'my $BASE="are belong to us"; sub BASE () { $BASE }; $BASE="fred"; print "all your base ", BASE' all your base fred

      Cheers,
      R.

      Pereant, qui ante nos nostra dixerunt!
Re: Using constants. What am I doing wrong?
by rlb3 (Deacon) on Feb 22, 2005 at 04:02 UTC
    Hello,
    A "use" statment is called at compile time, before any other code is evaluated. So when your constant is looking for $Base and it is not yet initialized. It might work if you put the $Base in a BEGIN block before the "use".

    rlb3

      update

      I am dumb, the one below does not work 'cos I put a my in the BEGIN block, when good habits turn bad! Without the my it works a charm

      >perl -le'BEGIN{$BASE="are belong to us"} use constant BASE => $BASE; print "all your base ", BASE' all your base are belong to us >

      original message

      I though that would work too but it does not for me

      > perl -le'BEGIN{$BASE="are belong to us"} use constant BASE => $BASE; print "all your base ", BASE' all your base > # but this does >perl -le'use constant BASE=>"are belong to us"; print "all your base ", BASE' all your base are belong to us >
      But I guess the OP was after something more flexible

      Cheers,
      R.

      Pereant, qui ante nos nostra dixerunt!