in reply to Lexical::Alias & subroutines

Update: I'm blind, can't read. (Ignore the contents of this post other than to -- it.). I, as jd points out, completely screwed this one up.

This is just a scoping issue. If you have a lexical at the outer scope and you declare a lexical at the inner scope (as in your example) the inner scope only sees the new version not the old. As you did the aliasing at the outer level and not the inner, the inner lexical isn't aliased. The outer will still be so once you return.

You could either, not declare the inner lexicals of the same name, OR alias the inner copy of $alias to $orig, and you would get the results you are expecting.

Like halley, I'm not quite sure why you would want to do this. $_[0] is already an alias for the first parameter passed. If that parameter is a reference, then using it as an lvalue will always affect the thing it refers to.

If the idea is to give a meaningful name to the parameter without copying the reference (a very cheap operation anyway) then you could go with defining a constant

use constant BYREF=>0; sub something{ $_[BYREF] = 1000 if $_[BYREF] > 1000; ... }

The win is minimal unless the sub is being called zillions of times, but using a defined CONSTANT cost nothing at runtime and is much cheaper than allocating a lexical and then calling a sub to alias it to $_[0], which is much more expensive that just assigning the ref to an local-scope lexical.


Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller

Replies are listed 'Best First'.
Re: Re: Lexical::Alias & subroutines
by jdporter (Paladin) on May 19, 2003 at 13:17 UTC
    This is just a scoping issue. If you have a lexical at the outer scope and you declare a lexical at the inner scope (as in your example) the inner scope only sees the new version not the old. As you did the aliasing at the outer level and not the inner, the inner lexical isn't aliased. The outer will still be so once you return.
    Nope, you're missing the point. He did exactly the same thing inside the sub as outside, independently... Yet it works outside the sub, but not inside. I agree that that is very unexpected behavior. I'd call it a bug.
    use Lexical::Alias; @a = (5); my $x = 1; alias($a[0],$x); print "$x\n"; # prints 5 sub foo { my $y = 2; alias($a[0],$y); print "$y\n"; # prints 2 } foo();

    jdporter
    The 6th Rule of Perl Club is -- There is no Rule #6.

Re: Re: Lexical::Alias & subroutines
by Jenda (Abbot) on May 19, 2003 at 15:09 UTC

    Of course it is possible to use the $_[CONST] (I do it myself from time to time), the problem is that the scope of the CONST is too wide. The constant is "global", defined in a package, so all subroutines in that package might use it, even if it doesn't make sense there. And if I had two functions that have the "conceptualy same" parameter on a different place I'd have to define two constants with similar names, which could be very confusing.

    Besides with the alias you can/could do something like

    sub foo { alias ($_[0] eq 'whatever' ? $_[1] : $_[2]) => my $x; ... }
    How's that written with constants?

    Another case when I'd love to have a lexical alias is when the function gets an array or hash reference, I do want to modify the array/hash, but do not like to have to dereference it all the time:

    sub foo { my ($aref) = @_; alias @$aref => my @ary; ... do something with @ary }
    You are right about the speed issues, but that's not the point. Readability is the main concern here.

    P.S.: Thinking about it some more. It's better that the alias() doesn't my() the variable.

    Jenda
    Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
       -- Rick Osborne

    Edit by castaway: Closed small tag in signature

      In your first example

      sub foo { my $x = $_[0] eq 'whatever' ? $_[1] : $_[2]; ... }

      Seems just as effective. But in your second, I agree. I've looked enviously at the perlsub examples of using globs to avoid the need to dereference refs and wished for a way to do the same thing with lexicals. Maybe Diotalevi's Lexical::TypeGlob would work for that? I haven't gotten around to playing with it yet.


      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller

        But it is not the same. Your code creates a copy. So the changes to $x do not affect the parameters to foo().

        Lexical::TypeGlob doesn't seem to be related.

        Jenda
        Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
           -- Rick Osborne

        Edit by castaway: Closed small tag in signature