Creating an alias to an existing hash (from a hash reference)

Discussion in 'Perl Misc' started by jl_post@hotmail.com, Dec 17, 2009.

  1. Guest

    Hi,

    Recently I was reviewing someone's Perl code and I saw that his
    code used a few global variables that were set and accessed by several
    functions. Since I am not a fan of global variables, I edited the
    code to get rid of all but one of them.

    (For the record, his code used "strict" and "warnings".)

    The remaining global variable was a hash. I proceded to edit the
    code so that the functions took a hash reference as an input
    argument. So previously, the code looked something like:

    my %hash;

    {
    f1();
    f2();
    f3();
    f4();
    }

    sub f1 { ... }
    sub f2 { ... }
    sub f3 { ... }
    sub f4 { ... }

    (This is a simplification.)

    I changed those lines to something like:

    sub f1 { ... }
    sub f2 { ... }
    sub f3 { ... }
    sub f4 { ... }

    {
    my %hash;

    f1(\%hash);
    f2(\%hash);
    f3(\%hash);
    f4(\%hash);
    }

    In the function definitions themselves, I added code to read in the
    input arguments, like this:

    sub f
    {
    my ($hashRef) = @_;
     
    , Dec 17, 2009
    #1
    1. Advertising

  2. C.DeRykus Guest

    On Dec 17, 2:52 pm, "" <> wrote:
    > ...
    >    However, since his code had "use strict;" in effect, "perl -c"
    > responded with:
    >
    > Variable "%hash" is not imported at ...
    >
    > So I declared %hash the line before with "my", like this:
    >
    >    my %hash;
    >    local *hash = $hashRef;
    >
    >    That didn't work; although it compiled just fine, %hash was empty.
    > So then I changed it to be declared with "our" instead of "my", like
    > this:
    >
    >    our %hash;
    >    local *hash = $hashRef;
    >
    > and that worked.  From then on in that function, every instance of
    > %hash pointed back to the passed-in %hash (that was passed in as a
    > reference).


    I was glad to hear about Data::Alias which's the way to go.
    However, 'no strict', used sparingly, may make sense in some
    cases too, particularly as an 'our' alternative:

    { no strict; local *hash = $hashRef; $hash{...} = ...; }

    --
    Charles DeRykus
     
    C.DeRykus, Dec 18, 2009
    #2
    1. Advertising

  3. Guest

    On Dec 18, 6:56 am, "C.DeRykus" <> wrote:
    > On Dec 17, 2:52 pm, "" <> > I wasglad to hear about Data::Alias which's the way to go.
    > However, 'no strict', used sparingly, may make sense in some
    > cases too, particularly as an 'our' alternative:
    >
    > { no strict; local *hash = $hashRef; $hash{...} = ...; }



    Actually, I'm pretty sure that, when "no strict" is in effect, all
    non-declared variables are automatically treated as package variables
    (that is, as if they were declared with "our").

    So it's not really an alternative to "our"; instead, that's all
    you'd be using (unless, of course, you explicitly use "my").

    (I tested it out with the following example:

    1. I started the Perl interpreter with: perl -wde 1

    2. Then I typed:

    use strict; { no strict; *blah = \%ENV; }

    3. Then I was able to reference %ENV through %blah outside
    of the scope %blah was fist used in, like this:

    print $blah{PATH};

    So disabling "strict" doesn't avoid the hazards of using "our",
    unfortunately.)

    And I agree with you that Data::Alias is definitely the way to go.
    I just wish it was a standard module so it could be used without
    having to install it explicitly.

    -- Jean-Luc
     
    , Dec 18, 2009
    #3
  4. Guest

    On Dec 17, 4:52 pm, Ben Morrow <> wrote:
    >     use Data::Alias;
    >
    >     sub f {
    >         my ($hashRef) = @_;
    >         alias my %hash = %$hashref;
    >         ...;
    >     }


    Thanks, Ben, yet again! I just installed Data::Alias from CPAN,
    and it works great.

    It would be nice if it were a standard module, so I could freely
    use it on code that is supposed to run on plain Perl installations
    (where I have no control over which Perl modules are installed).

    If I find myself in such a situation in the future (which I'm sure
    will happen), I'll probably just resort to search-and-replacing
    instances of "$hash{" to "$hashRef->{".

    But if I'm in a situation where I'm free to use CPAN modules, I'll
    probably be making good use of Data::Alias.

    Thanks again, Ben.

    -- Jean-Luc
     
    , Dec 18, 2009
    #4
  5. Guest

    > On Thu, 17 Dec 2009 14:52:16 -0800, wrote:
    > > The idea of creating a new variable named %hash came to mind:

    >
    > > sub f
    > > {
    > >    my ($hashRef) = @_;
    > >    my %hash = %$hashRef;
    > >    .
    > >    .
    > >    .
    > > }

    >
    > > but that would create a completely new copy of the original
    > > %hash (using extra memory),



    On Dec 17, 7:54 pm, Ruben Safir <> wrote:
    > Oh.. - why do you say that?



    Because when you make a copy of a hash, a completely separate copy
    is made. Consider this code:

    my %hash = %ENV;

    or even:

    my $hashRef = \%ENV;
    my %hash = %$hashRef;

    With either approach, %hash is now equivalent to %ENV, but only
    temporarily, since it is a completely separate hash. If you add a new
    entry to %hash, like this:

    $hash{apple} = 'banana';

    that same entry won't exist in %ENV. Likewise, if %ENV is modified
    (for whatever reason), that modification won't carry over to %hash.

    I hope this clarifies things, Ruben.

    -- Jean-Luc
     
    , Dec 18, 2009
    #5
  6. C.DeRykus Guest

    On Dec 18, 8:32 am, "" <> wrote:
    > On Dec 18, 6:56 am, "C.DeRykus" <> wrote:
    >
    > > On Dec 17, 2:52 pm, "" <> > I was glad to hear about Data::Alias which's the way to go.
    > > However, 'no strict', used sparingly, may make sense in some
    > > cases too, particularly as an 'our' alternative:

    >
    > > { no strict; local *hash = $hashRef; $hash{...} = ...; }

    >
    >    Actually, I'm pretty sure that, when "no strict" is in effect, all
    > non-declared variables are automatically treated as package variables
    > (that is, as if they were declared with "our").
    >


    No, ordinary package variables and those declared with
    'our' are scoped differently. And 'our' can be clobbered
    in a multi-package global way that ordinary package
    variables won't be:

    perl -Mstrict -wle "package main; our $x=1;
    package Foo; our $x=2;
    package main; print $x"
    2

    vs.

    perl -Mstrict -wle "package main; use vars '$x';$x=1;
    package Foo; use vars '$x';$x=2;
    package main; print $x"
    1


    >
    >    So it's not really an alternative to "our"; instead, that's all
    > you'd be using (unless, of course, you explicitly use "my").
    >
    >    (I tested it out with the following example:
    >
    > 1. I started the Perl interpreter with:  perl -wde 1
    >
    > 2. Then I typed:
    >
    >       use strict; { no strict; *blah = \%ENV; }
    >
    > 3. Then I was able to reference %ENV through %blah outside
    >    of the scope %blah was fist used in, like this:
    >
    >       print $blah{PATH};
    >
    >    So disabling "strict" doesn't avoid the hazards of using "our",
    > unfortunately.)
    >


    Hm, you didn't declare 'blah' or localize inside the
    {no strict;...} so that won't compile outside of the
    debugger:

    perl -Mstrict -le "{no strict; *blah = \%ENV;}
    print $blah{PATH}"
    Variable "%blah" is not imported ...
    Global symbol "%blah" requires explicit package name...


    But with those corrections, the first print below
    works as expected and the final print outside the
    {no strict;...} draws an uninitialized warning:


    perl -Mstrict -wle "use vars '%blah';
    {no strict; local *blah = \%ENV; print $blah{PATH};}
    print $blah{PATH}"

    --
    Charles DeRykus
     
    C.DeRykus, Dec 18, 2009
    #6
  7. wrote:

    > If I find myself in such a situation in the future (which I'm sure
    > will happen), I'll probably just resort to search-and-replacing
    > instances of "$hash{" to "$hashRef->{".


    Don't forget about replacing "@hash{" with "@{$hashRef}{", and "keys
    %hash" with "keys %$hashRef", etc.

    Xho
     
    Xho Jingleheimerschmidt, Dec 18, 2009
    #7
  8. Guest

    On Dec 18, 12:55 pm, "C.DeRykus" <> wrote:
    > the first print below
    > works  as expected and the final print outside the
    > {no strict;...} draws an uninitialized warning:
    >
    > perl -Mstrict -wle "use vars '%blah';
    >       {no strict; local *blah = \%ENV; print $blah{PATH};}
    >       print $blah{PATH}"



    True, but the uninitialized warning happened because you used the
    "local" keyword. If you remove that, then the second print() line
    will have access to %ENV via %blah.

    So you might think that using "local" prevents code in outside
    scopes from accessing %ENV through %blah. But that's not true. The
    "local" keyword temporarily changes the value of %blah, but it changes
    it everywhere in the package, not just in its scope.

    Consider this code:

    perl -Mstrict -wle "{no strict; local *blah = \%ENV; f() }
    sub f { our %blah; print $blah{PATH} }

    Even though the code inside f() is in a completely different scope
    that the code that calls f(), the code inside f() still has access to
    %blah as the calling code sees it (and therefore has access to modify
    %ENV through it).

    Sure, declaring *blah as "local" in f() would prevent that from
    happening, but since you can't always guarantee that all code will
    "local"ize all its typeglobs, declaring one typeglob as "local" won't
    necessarily stop all code (outside the intended scope) from accessing
    what %blah references. (It'll stop some code, but not all code.)

    Cheers,

    -- Jean-Luc
     
    , Dec 18, 2009
    #8
  9. Guest

    > wrote:
    > >    If I find myself in such a situation in the future (which I'm sure
    > > will happen), I'll probably just resort to search-and-replacing
    > > instances of "$hash{" to "$hashRef->{".


    On Dec 18, 1:09 pm, Xho Jingleheimerschmidt <>
    replied:
    > Don't forget about replacing "@hash{" with "@{$hashRef}{", and "keys
    > %hash" with "keys %$hashRef", etc.



    Very true. Yet another reason Data::Alias is so nice.

    -- Jean-Luc
     
    , Dec 18, 2009
    #9
  10. Guest

    On Dec 18, 12:55 pm, "C.DeRykus" <> wrote:
    > No, ordinary package variables and those declared with
    > 'our' are scoped differently. And 'our' can be clobbered
    > in a multi-package global way that ordinary package
    > variables won't be:
    >
    >   perl -Mstrict -wle "package main; our $x=1;
    >                       package Foo;  our $x=2;
    >                       package main; print $x"
    >   2
    >
    > vs.
    >
    >   perl -Mstrict -wle "package main; use vars '$x';$x=1;
    >                       package Foo;  use vars '$x';$x=2;
    >                       package main; print $x"
    >   1



    Interesting. I did not know that.

    "perldoc -f our" helped me understand a little more.

    Of course, if your scopes don't cross package boundaries, then this
    isn't an issue to worry about. But if they do, then this is good to
    know.

    -- Jean-Luc
     
    , Dec 18, 2009
    #10
  11. C.DeRykus Guest

    On Dec 18, 12:57 pm, "" <>
    wrote:
    > On Dec 18, 12:55 pm, "C.DeRykus" <> wrote:
    >
    > > the first print below
    > > works  as expected and the final print outside the
    > > {no strict;...} draws an uninitialized warning:

    >
    > > perl -Mstrict -wle "use vars '%blah';
    > >       {no strict; local *blah = \%ENV; print $blah{PATH};}
    > >       print $blah{PATH}"

    >
    >    True, but the uninitialized warning happened because you used the
    > "local" keyword.  If you remove that, then the second print() line
    > will have access to %ENV via %blah.


    True but it can be a good idea in general to
    insulate a variable with 'local' to avoid
    avoid clobbering any potential existing values.
    I thought you had control of that part of the
    code...

    >
    >    So you might think that using "local" prevents code in outside
    > scopes from accessing %ENV through %blah.  But that's not true.  The
    > "local" keyword temporarily changes the value of %blah, but it changes
    > it everywhere in the package, not just in its scope.
    >
    >    Consider this code:
    >
    >    perl -Mstrict -wle "{no strict; local *blah = \%ENV; f() }
    >                        sub f { our %blah; print $blah{PATH} }
    >
    > Even though the code inside f() is in a completely different scope
    > that the code that calls f(), the code inside f() still has access to
    > %blah as the calling code sees it (and therefore has access to modify
    > %ENV through it).
    >
    >    Sure, declaring *blah as "local" in f() would prevent that from
    > happening, but since you can't always guarantee that all code will
    > "local"ize all its typeglobs, declaring one typeglob as "local" won't
    > necessarily stop all code (outside the intended scope) from accessing
    > what %blah references.  (It'll stop some code, but not all code.)
    >


    That's expected because 'local's dynamic scoping
    propagates the localized variable into any called
    subroutine in the localized scope. For instance:

    { local $foo='bar'; f(); }

    "The f() or any sub called within f() all the way
    down the call stack will see $foo with its local
    value 'bar'.

    So, used correctly, 'local' does limit what's seen.
    There's quite a bit of confusion about the gory
    details of 'local' however. And details in perlsub
    and perlfaq7 are skimpy..

    --
    Charles DeRykus
     
    C.DeRykus, Dec 18, 2009
    #11
  12. C.DeRykus Guest

    On Dec 21, 11:05 am, Ben Morrow <> wrote:
    > Quoth "C.DeRykus" <>:
    >
    >
    >
    > > So, used correctly, 'local' does limit what's seen.
    > > There's quite a bit of confusion  about the gory
    > > details of 'local' however. And details in perlsub
    > > and perlfaq7 are skimpy..

    >
    > What about local's behaviour is unclear to you?
    >


    Plenty :) but I just intending to say that there's
    more to 'local' than a quick peek at the docs might
    show. There're some caveats/subtleties to 'local'.
    as well as the need for understanding 'my vs. local',
    and 'lexical vs. dynamic' scoping issues, etc.. Even
    the word 'local' is a bit of a mis-nomer. Lots of
    good info in perlsub but close, careful look(s) are
    needed. Fun for young and old alike...

    I can't find it now but there was a lengthy thread I just
    saw yesterday (and now can't find) that dealt with what
    appeared to be buggy behavior of local. I think Abigail
    demo'ed a short code example to make the case for a bug.
    Others, arguably more correct, countered the "bug' was
    just a 'feature' due to the way 'local' was implemented.

    --
    Charles DeRykus
     
    C.DeRykus, Dec 21, 2009
    #12
  13. C.DeRykus Guest

    On Dec 21, 3:57 pm, "C.DeRykus" <> wrote:
    > ...
    > I can't find it now but there was a lengthy thread I just
    > saw yesterday (and now can't find)  that dealt with what
    > appeared to be buggy behavior of local. I think Abigail
    > demo'ed a short code example to make the case for a bug.
    > Others, arguably more correct, countered the "bug' was
    > just a 'feature' due to the way 'local' was implemented.
    >


    Still can't find the thread but I think
    the code was kinda/sorta like:

    use strict;
    use warnings;
    use vars qw/$foo $bar/;
    $foo = 3;
    $bar = \$foo;
    {
    local $foo = 4;
    print $$bar; # 3 not 4!
    }


    --
    Charles DeRykus
     
    C.DeRykus, Dec 22, 2009
    #13
  14. Marc Girod Guest

    On Dec 22, 5:26 am, Ben Morrow <> wrote:

    > there are actually
    > three levels: 'name', 'container' and 'value'.


    Excellent discussion, which could be generalized
    to a critique of the concept of 'high-level'.

    High-level means: 'simpler on the surface'.
    Low-level means: 'simpler at depth'.

    Weren't you explaining a high-level concept
    by the means of its (simpler) low-level
    implementation?

    Marc
     
    Marc Girod, Dec 22, 2009
    #14
  15. C.DeRykus Guest

    On Dec 21, 9:26 pm, Ben Morrow <> wrote:
    > Quoth "C.DeRykus" <>:
    >
    >
    >
    > 'local' takes the name you pass it, records which container it points to
    > to be restored at the end of the scope, and creates a new container for
    > the name to point to until then. (This is why 'local' variables start
    > out empty.) When you say
    >
    >     $bar = \$foo;
    >
    > above, you are putting a reference to the *current* container for $foo
    > into $bar; this reference is now completely divorced from the name
    > '$foo' and is unaffected by 'local' pointing that name somewhere else.


    Thanks, great explanation.

    And addresses confirm that the localized address
    is now 'somewhere else':

    perl -wle "no strict; $foo='foobar'; $bar=\$foo; print \$foo;
    { local $foo = 'foobar1'; print \$foo; }"
    SCALAR(0x16808e4)
    SCALAR(0x2b7b14)

    >
    > Note that this is only true of Perl 5-style hard refs: Perl 4-style
    > symrefs point to a name (after all, they're only strings) so
    >
    >     no strict;
    >     $foo = 3;
    >     $bar = "foo";
    >     {
    >         local $foo = 4;
    >         say $$bar;
    >     }
    >
    > will see the localized value for $foo, as you might have expected.


    Good 'ole slow, straightforward symrefs ;)

    >
    > (I should probably point out that this explanation is also incomplete
    > :). In particular, it doesn't cover cases like
    >
    >     local $foo{bar};
    >     local $$foo;
    > )
    >


    --
    Charles DeRykus
     
    C.DeRykus, Dec 22, 2009
    #15
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. nrm
    Replies:
    3
    Views:
    579
  2. grocery_stocker
    Replies:
    9
    Views:
    818
    grocery_stocker
    May 24, 2008
  3. rp
    Replies:
    1
    Views:
    587
    red floyd
    Nov 10, 2011
  4. Replies:
    0
    Views:
    216
  5. JustMe
    Replies:
    1
    Views:
    189
    Tassilo v. Parseval
    Aug 29, 2003
Loading...

Share This Page