Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Why so strict?

by mikeh123 (Novice)
on Nov 12, 2014 at 02:50 UTC ( [id://1106927]=perlquestion: print w/replies, xml ) Need Help??

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

Howdy Monks. I don't often ask, but this one's got me:

my $c = &func() ? say "$c found!" : say "None!";
Fails with: Global symbol "$c" requires explicit package name. Why doesn't this variable declaration work in this place?

Yet, of course:

my $c; $c = &func() ? say "$c found!" : say "None!";
Works just fine. Did some due diligence trying to search, but as you can imagine, this example of failure is hard to find! Thanks!

Replies are listed 'Best First'.
Re: Why so strict?
by Loops (Curate) on Nov 12, 2014 at 03:21 UTC

    What you're employing is the Ternary operator which has the form:

    $variable = <condition> ? <value1> : <value2>;

    The variable gets set to value1 if the condition resolves to true, or value2 if the condition resolves to false. So you should not be using "say" in either the value1 or value2 positions as you do in your example. So lets rewrite it without the say:

    my $c = <true/false> ? "$c found!" : "None!";

    And now the problem is clear, in the true case, you're trying to initialize $c to a value that contains _itself_. It's like saying my $c = $c, it's nonsensical.

      Thanks to both of you for the clarity! For far too long I've thought of the ternary operator as, well, not an operator, but a concise shorthand for if/else. Perfectly and quickly answered; thanks for sharing the wisdom!
Re: Why so strict?
by GrandFather (Saint) on Nov 12, 2014 at 03:37 UTC

    I'm guessing that's a mocked up example derived from some "real" code because as it stands it doesn't make sense on a bunch of levels.

    1/ say doesn't return much that's useful (true on success, but printing to the console wil pretty much always succeed). Both invocations of say will return the same result so $c gets the same value regardless.

    2/ Maybe what you really wanted was to say $c, not the contents of $c. In that case you should either have written "\$c ..." or '$c ...'.

    3/ We don't usually use & in function calls now, just write func().

    Perl is the programming world's equivalent of English
Re: Why so strict?
by eyepopslikeamosquito (Archbishop) on Nov 12, 2014 at 05:31 UTC

    To better understand how Perl parses your code, run:

    perl -MO=Deparse,-p yourscript.pl
    and you will see something like:
    my($c); ($c = (&func() ? say("$c found!") : say('None!')));
    That is, the return value of say (which will almost certainly be the value one) is always being assigned to $c! I doubt that is what you want. To see that more clearly, print out the value of $c after your assignment statement.

    See also: Surprised by Perl parse of ternary operator.

Re: Why so strict? (diagnostics)
by Anonymous Monk on Nov 12, 2014 at 03:10 UTC

    Because thats how its supposed to work :) strict, diagnostics, splain...the spirit of strict ...

    $ perl -e " use diagnostics; my $c = $c; " Name "main::c" used only once: possible typo at -e line 1 (#1) (W once) Typographical errors often show up as unique variable nam +es. If you had a good reason for having a unique name, then just menti +on it again somehow to suppress the message. The our declaration is provided for this purpose. NOTE: This warning detects symbols that have been used only once s +o $c, @c, %c, *c, &c, sub c{}, c(), and c (the filehandle or format) are con +sidered the same; if a program uses $c only once but also uses any of the +others it will not trigger this warning.

    The $c on the right side of my $c = is the global variable $main::c, and $main::c is not the same as $c

    Also

    $ perl -e " use diagnostics; my $c = $c; my $c = $c; " "my" variable $c masks earlier declaration in same scope at -e line 1 +(#1) (W misc) A "my", "our" or "state" variable has been redeclared in +the current scope or statement, effectively eliminating all access to +the previous instance. This is almost always a typographical error. +Note that the earlier variable will still exist until the end of the sc +ope or until all closure referents to it are destroyed. Name "main::c" used only once: possible typo at -e line 1 (#2) (W once) Typographical errors often show up as unique variable nam +es. If you had a good reason for having a unique name, then just menti +on it again somehow to suppress the message. The our declaration is provided for this purpose. NOTE: This warning detects symbols that have been used only once s +o $c, @c, %c, *c, &c, sub c{}, c(), and c (the filehandle or format) are con +sidered the same; if a program uses $c only once but also uses any of the +others it will not trigger this warning.

    So its  my $c = $main::c;  my $c = $c; and the second lexical $c takes places of the original lexical $c (my $c) ... so the first my $c is invisible

Re: Why so strict?
by Laurent_R (Canon) on Nov 12, 2014 at 07:32 UTC
    Several issues have been pointed out in the presented code, but the main one is that when you write:
    my $c = ...
    $c is not really declared until after the end of the current instruction. BTW, this is different in Perl 6, where $c gets declared immediately, before the assignment is actually executed. I am not really sure of what it is good for (it may be useful for some complicated instructions doing several things in one step), but that's anyway a difference between Perl 5 and Perl 6.
Re: Why so strict?
by MidLifeXis (Monsignor) on Nov 12, 2014 at 14:20 UTC

    There is also a possible precedence issue with your statement. If you meant:

    $c = &func(); $c ? say "$c found!" : say "None!";
    and not
    $c = (&func() ? say "$c found!" : say "None!");
    then you got it wrong. ?: has a higher precedence than assignment (see perlop), so the ternary operator binds tighter to its operands than does the assignment operator. The ternary operator is handled first, then the assignment operator. To illustrate, try
    perl -Mstrict -E 'sub func {5}; my $c; my $results = ( $c=func() ? 1 : + 2); say $c, "\t", $results'
    and
    perl -Mstrict -E 'sub func {5}; my $c; my $results = ( $c=func()) ? 1 +: 2; say $c, "\t", $results'

    --MidLifeXis

Re: Why so strict?
by ww (Archbishop) on Nov 12, 2014 at 15:40 UTC

    You say, re your second code block, "Works just fine."

    That's interesting. My milage varies:

    C:\>perl -E "use 5.018; use strict; my $c; $c = &func() ? say '$c foun +d!' : say 'None!';" Undefined subroutine &main::func called at -e line 1.
    ... but...
    C:\>perl -E "use 5.018; use strict; sub func {say 'in func()';}my $c; +$c = &func() ? say '$c found!' : say 'None!';" in func() $c found!

    Aside from returning the declaration of $c to the one liner and the variant quoting, I see no diffs. Can you explain?


    ++$anecdote ne $data


      The original post quite possibly did not contain the full code. Maybe the func subroutine is defined somewhere else.
Re: Why so strict?
by ikegami (Patriarch) on Nov 13, 2014 at 18:01 UTC
    First of all,
    my $c = &func() ? say "$c found!" : say "None!";
    means
    my $c = ( &func() ? say "$c found!" : say "None!" );

    Neither my $c nor the assignment has been evaluated when you tried to read $c. You meant

    ( my $c = &func() ) ? say "$c found!" : say "None!";

    Fixing that error won't fix the error you see, though. Lexical variables only become visible the statement after the one in which they are created in order to allow the following to work.

    my $x = 123; { my $x = $x; say $x; # 123 $x = 456; say $x; # 456 } say $x; # 123

    Anyway,

    my $c = func(); say $c ? "$c found!" : "None!";
    is much clearer than the following cleaned-up but still non-functional version of your code:
    say( ( my $c = func() ) ? "$c found!" : "None!" );
Re: Why so strict?
by LanX (Saint) on Nov 13, 2014 at 01:03 UTC
    It's documented somewhere, as Laurent already said is my only effecting the symbols after the current statement.

    Reason for this is to be able to write something like  my $x=$x+1

    Cheers Rolf

    (addicted to the Perl Programming Language and ☆☆☆☆ :)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1106927]
Approved by Loops
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (3)
As of 2024-04-20 04:29 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found