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

Trying to compile this code:
#!perl use strict; use warnings; use 5.020; my @Org = (9, 1,0); my $N= #Org; say "N = $N"; say @Org;
But getting this error: Global symbol "$N" requires explicit package name (did you forget to declare "my $N"?) at code.pl line 12. syntax error at code.pl line 14, near "say" Execution of code.pl aborted due to compilation errors. What do I do wrong?

Sorry for a stupid question! But I want to learn: 've seen this kind of error many times in my programs -- probably I'm missing something very basic.

Thank you! :)

Replies are listed 'Best First'.
Re: Strange compile error?
by marto (Cardinal) on Apr 29, 2024 at 16:38 UTC
    my $N= #Org;

    If you want to get the length of the array do:

    my $N = scalar( @Org );

    You may have been thinking of:

    my $N = $#Org;

    Which gives you the index of the last element, probably not what you're looking for.

      > my $N = scalar( @Org );

      That's explicit and correct, tho for completeness

      my $N = @Org;

      has the same implicit effect, since it's a scalar assignment. (The left hand side is a scalar)

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      see Wikisyntax for the Monastery

Re: Strange compile error?
by LanX (Saint) on Apr 29, 2024 at 17:20 UTC

    Others already told you how to do right...

    ... But you asked:

    > What do I do wrong?

    Point is, that # "normally" starts a comment, and you wrote

    my $N= #Org; say "N = $N";

    So what the compiler effectively sees is a multiline statement, semantically equal to

    my $N= say "N = $N";

    The declaration my $N at the beginning only takes effect after this statement, i.e. behind the semicolon.

    Hence, the second $N is undeclared.

    Hope the error messages are clearer now. :)

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    see Wikisyntax for the Monastery

Re: Strange compile error?
by hippo (Archbishop) on Apr 29, 2024 at 17:27 UTC
    my $N= #Org; ... seen this kind of error many times in my programs

    If you find you make this sort of error frequently then it would probably be worth enabling syntax highlighting in your editor. It should then be really apparent that you have started a comment where you did not mean to.


    🦛

Re: Strange compile error?
by kcott (Archbishop) on Apr 29, 2024 at 18:11 UTC

    G'day gelbukh,

    Welcome to the Monastery.

    "Sorry for a stupid question! But I want to learn: ..."
    • Not a "stupid question"!
    • ++ for "I want to learn".
    • Here's a description of what's going on.

    A '#' introduces a comment. See "perlsyn: Comments". So, when compiling, Perl sees your lines 9 to 12 as:

    my $N= say "N = $N";

    As Perl doesn't care about the intervening whitespace, that's basically:

    my $N= say "N = $N";

    Assignment is a right-to-left operation. See "perlop - Perl operators and precedence". That's a fairly long page; the parts most pertinent to your question are:

    So, Perl attempts to compile 'say "N = $N"' first. It hasn't evaluated the left side of the assignment ('my $N') yet, so it sees $N as a "Global symbol" and hence the error message.

    There is a subtle point here that isn't immediately, or intuitively, obvious. A statement such as 'my $x = ...;' has two distinct parts:

    • 'my $x' declares $x as a lexical variable at compile time.
    • The whole statement 'my $x = ...;' is compiled at compile time; however, the actual assignment is a runtime operation.

    I see a couple of posts showing how to get length and last index of an array. Another way to get the length is:

    my $N= 0+@Org;

    As a further tangential point, a "use VERSION" statement, where VERSION is 5.12 or greater, you get 'use strict;' automatically. I like to put the use VERSION statement first: if the user does not have a sufficiently high enough version, you might as well stop here rather than doing other (effectively) pointless processing. Accordingly, instead of

    use strict; use warnings; use 5.020;

    I'd write

    use 5.020; use warnings;

    Just something to consider for future reference.

    — Ken

      A '#' introduces a comment.

      Oh no! You triggered that annoying little bean counter! So here we go ...

      A '#' does not ALWAYS introduce a comment:

      • $#array is the last index of @array
      • # can be used in place of / in s///, m//, q//, qq//, qx//, qw//, y///, tr///.
      • $# was a magic variable, deprecated long ago, removed in Perl 5.10.0 (see perlvar)
      • # inside a comment is ignored like any other character until end of line
      • And of course, a # in a string constant is just that. It does not start a comment inside a string constant.

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
        BUT ...

        • Inside POD, you forgot POD.

        WAIT...

        • After __DATA__ and __END__

        STOP ...

        • could be inside a here-doc marker too
        MOMENT ...

        • A source filter could transform them (see half of f*ck!ng ACME:: ...)

        HOLD ...

        • what if C-preprocessor macros are activated?
        AND ...
        • (fill in more nitpicking, yawn 🥱)

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        see Wikisyntax for the Monastery

        UPDATES

        Inserted 3 more criteria in hindsight... 🙃

      > Assignment is a right-to-left operation

      That's right, but sorry you are overcomplicating things.

      Precedence isn't relevant here:

      DB<1> use strict; my $N = $N; Global symbol "$N" requires explicit package

      Declarations are only effective after the statement, in this case behind the semicolon.

      This was done to allow accessing equally named variables from a surrounding scope.

      See perlsub#Private-Variables-via-my()

      The declared variable is not introduced (is not visible) until after the current statement. Thus,

       my $x = $x; 

      can be used to initialize the new $x with the value of the old $x, and the expression

       my $x = 123 and $x == 123 

      is false unless the old $x happened to have the value 123.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      see Wikisyntax for the Monastery

        I was talking about associativity (as in "right-to-left" operation). The table to which I referred lumps associativity and precedence together: there's not a lot I can do about that.

        — Ken

Re: Strange compile error?
by gelbukh (Initiate) on Apr 29, 2024 at 20:03 UTC
    OOPS, I don't know how to remove my question or edit it. Yes it was a trivial error. What I wanted to say was: my $N= $#Org, but I forgot the $, so the rest of the line was a comment, and the my statement was unfinished. Now I see. I don't know how to remove this question
      > OOPS, I don't know how to remove my question

      No need to remove a question. Many people will read the thread and will learn from the discussion. Even in the far future.

      That's how a board works :)

      So don't worry.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      see Wikisyntax for the Monastery

Re: Strange compile error?
by 1nickt (Canon) on Apr 29, 2024 at 16:41 UTC

    Hi,

    For the length of an array you need $#, i.e. $#Org.

    Ignore this, it's a blunder.


    The way forward always starts with a minimal test.