Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask

Not sure how to handle this scope

by misterperl (Monk)
on Aug 18, 2021 at 17:59 UTC ( #11135932=perlquestion: print w/replies, xml ) Need Help??

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

I want to use the same name for a var above and inside braces, but in some cases, I want to make a local copy to use in the braces:
# sorta like my $self = new OO( $cat ); { my $self = new OO( $dog ) if $ARGV[0] eq 'Fido'; say $self->species(); }
.. but at the "say" line, self is undef when ARGV[0] ne 'Fido'; Which surprised me, since I thought OK- it wont create a new scope of $self in the braces, so the scope above should persist? I also tried ( my $self = new OO( $dog ) ) if $ARGV[0] eq 'Fido'; which I thought had an even better chance to succeed but didn't.

Seems counter-intuitive that ANY part inside of ( ) would have any influence, if followed by "if 0"?

When I emerge from the braces I want the original self there, and I dont want to use another variable name since I have hundreds of "self" refs in the braces... I also tried "local" instead of "my" but got a lexical error in that case.


Replies are listed 'Best First'.
Re: Not sure how to handle this scope (updated)
by haukex (Bishop) on Aug 18, 2021 at 18:04 UTC

    I wouldn't re-use the same variable name for a lexical that has already been defined. Also, don't put a postfix if on a my, as its behavior is undefined - see the note at the bottom of the section Statement Modifiers. Instead, you could do:

    my $self = OO->new( $cat ); { my $inner_self = $ARGV[0] eq 'Fido' ? OO->new( $dog ) : $self; say $inner_self->species(); }

    Note you shouldn't use Indirect Object Syntax either.

    Update: Added some details to the above. Plus, why don't you just do this?

    my $self = OO->new( $ARGV[0] eq 'Fido' ? $dog : $cat );

    It's also a bit unusual to use $self as the variable name for a newly created object, since $self is usually used as the first argument to a method call, i.e. it's an existing object.

      Strongly agree. "Re-using" a variable name, particularly one like $self, is a recipe for obtuse code that will be very difficult for your inevitable successor to understand and debug.
        Thanks guys, I left out a lot of details- but the { } are actually a forked loop and the self that contains the mysql handle goes away for each fork. That's why I'm trying to do this- BUT I want to run sometimes forked , and sometimes not, and for the not case- I want to use the object from outside the loop.. I realize this if pretty fugly but there is a lot of motivation to do it.

        But aisde from all that the real question is why does self go undef, and not use the scope outside the braces?

Re: Not sure how to handle this scope
by tybalt89 (Prior) on Aug 18, 2021 at 19:12 UTC

    Something like this? (simplified...)

    #!/usr/bin/perl use strict; use warnings; my $self = 'cat'; print "outside $self\n"; { my $self = $self; print " inside $self\n"; $self = 'dog' if not defined $ARGV[0]; print " inside $self\n"; } print "outside $self\n";


    outside cat inside cat inside dog outside cat

      Itís silly and off topic but I am compelled to quote it for the tangent.

      Outside of a dog, a book is a manís best friend. Inside of a dog, itís too dark to read.
Re: Not sure how to handle this scope
by BillKSmith (Monsignor) on Aug 19, 2021 at 01:34 UTC
    In this respect, lexical variables are much like local. The new variable is not initialized.
    use strict; use warnings; use feature 'say'; package OO; sub new {my $animal = $_[1]; return bless \$animal;} sub species { return ${$_[0]} } package main; my $cat = 'cat'; my $dog = 'dog'; my $self = new OO( $cat ); { my $self = $self; $self = new OO( $dog ) if $ARGV[0] eq 'Fido'; say $self->species(); } say $self->species();

    OUTPUT (with argument 'Fido')

    dog cat

    OUTPUT (without argument 'Fido')

    cat cat
Re: Not sure how to handle this scope
by Anonymous Monk on Aug 19, 2021 at 13:52 UTC

    Braces always create a new scope, and my always creates a lexical variable, which is undef by default -- or at least, should be. In practice the behavior of my $x = 'foo' if $bar is undefined if the condition is false, and is documented as such.

    Since the scope of a lexical variable begins at the statement after the statement that defines it, the ternary operator does what you want: my $self = $ARGV[0] eq 'Fido' ? OO->new( $dog ) : $self;. The $self in the assignment statement refers to the variable outside the braces, since the variable inside the braces is not yet in-scope.

      "Braces always create a new scope"

      Unless they create a $hash ={a=>1} or are used for enclosing ${identifiers} or are used to dereference a $hash->{a} ... or...?

      - Ron

        Quite right. In trying to address the OP's statement that ... it wont create a new scope of $self in the braces ... I overstated the case. Thank you for the correction.

Log In?

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

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (3)
As of 2022-01-22 19:01 GMT
Find Nodes?
    Voting Booth?
    In 2022, my preferred method to securely store passwords is:

    Results (63 votes). Check out past polls.