access anonymous variable

Discussion in 'Perl Misc' started by George Mpouras, Feb 1, 2011.

  1. At the following example I want to alter the value of $counter variable ,
    but without using the the $iter code reference.
    I 've tried many tricks using __ANON__ but without luck . Can you help ?


    my $iter = Create_counter( 37);

    for (1..3)
    {
    print "$_) ". $iter->() ."\n"
    }

    sub Create_counter
    {
    my $counter = $_[0];

    return sub
    {
    $counter++
    }
    }
    George Mpouras, Feb 1, 2011
    #1
    1. Advertising

  2. George Mpouras

    Ted Zlatanov Guest

    On Tue, 1 Feb 2011 14:20:58 +0200 "George Mpouras" <> wrote:

    GM> At the following example I want to alter the value of $counter variable ,
    GM> but without using the the $iter code reference.
    GM> I 've tried many tricks using __ANON__ but without luck . Can you help ?

    GM> my $iter = Create_counter( 37);

    GM> for (1..3)
    GM> {
    GM> print "$_) ". $iter->() ."\n"
    GM> }

    GM> sub Create_counter
    GM> {
    GM> my $counter = $_[0];

    GM> return sub
    GM> {
    GM> $counter++
    GM> }
    GM> }

    Here's one way:

    #!/usr/bin/perl

    use warnings;
    use strict;
    use Modern::perl;

    {
    my $counter = 0;

    sub get_counter
    {
    $counter = shift @_ if scalar @_;
    return \$counter;
    }
    }

    ${get_counter(37)}++; # increments the hidden $counter, starting at 37
    say ${get_counter()};
    ${get_counter()}++; # increments the hidden $counter
    say ${get_counter()};

    This passes around a reference to a scoped variable; there's no other
    way to access $counter outside its scope and the value of $counter will
    persist between get_counter() calls.

    I'll warn you that this is probably the wrong way to go unless you
    really need this and know why. Can you explain your requirements a
    little bit?

    Ted
    Ted Zlatanov, Feb 1, 2011
    #2
    1. Advertising

  3. "George Mpouras" <> writes:

    > At the following example I want to alter the value of $counter variable ,
    > but without using the the $iter code reference.


    If you really need this, it can be done with the PadWalker module. But
    I would recommend against it unless you know what you are doing and
    are sure that you need to do it.

    //Makholm
    Peter Makholm, Feb 1, 2011
    #3
  4. Στις 1/2/2011 5:25 μμ, ο/η Ted Zlatanov έγÏαψε:
    > On Tue, 1 Feb 2011 14:20:58 +0200 "George Mpouras"<> wrote:
    >
    > GM> At the following example I want to alter the value of $counter variable ,
    > GM> but without using the the $iter code reference.
    > GM> I 've tried many tricks using __ANON__ but without luck . Can you help ?
    >
    > GM> my $iter = Create_counter( 37);
    >
    > GM> for (1..3)
    > GM> {
    > GM> print "$_) ". $iter->() ."\n"
    > GM> }
    >
    > GM> sub Create_counter
    > GM> {
    > GM> my $counter = $_[0];
    >
    > GM> return sub
    > GM> {
    > GM> $counter++
    > GM> }
    > GM> }
    >
    > Here's one way:
    >
    > #!/usr/bin/perl
    >
    > use warnings;
    > use strict;
    > use Modern::perl;
    >
    > {
    > my $counter = 0;
    >
    > sub get_counter
    > {
    > $counter = shift @_ if scalar @_;
    > return \$counter;
    > }
    > }
    >
    > ${get_counter(37)}++; # increments the hidden $counter, starting at 37
    > say ${get_counter()};
    > ${get_counter()}++; # increments the hidden $counter
    > say ${get_counter()};
    >
    > This passes around a reference to a scoped variable; there's no other
    > way to access $counter outside its scope and the value of $counter will
    > persist between get_counter() calls.
    >
    > I'll warn you that this is probably the wrong way to go unless you
    > really need this and know why. Can you explain your requirements a
    > little bit?
    >
    > Ted



    I was doing some experiments after a discussion with my colleague about
    iterators and how they can protect their variables. I thought I could
    find a way for direct access private variable of an anonymous subroutine
    but maybe it is impossible after all. They are completely invisible.

    use Data::Dumper;
    $Data::Dumper::Deparse=1;
    print STDOUT Data::Dumper::Dumper(\%{__PACKAGE__.'::'});
    George Mpouras, Feb 1, 2011
    #4
  5. George Mpouras

    Ted Zlatanov Guest

    On Tue, 01 Feb 2011 22:35:55 +0200 George Mpouras <> wrote:

    GM> I was doing some experiments after a discussion with my colleague
    GM> about iterators and how they can protect their variables. I thought I
    GM> could find a way for direct access private variable of an anonymous
    GM> subroutine but maybe it is impossible after all. They are completely
    GM> invisible.

    GM> use Data::Dumper;
    GM> $Data::Dumper::Deparse=1;
    GM> print STDOUT Data::Dumper::Dumper(\%{__PACKAGE__.'::'});

    The example I gave shows how to have a scope that keeps a private
    variable whose value is preserved between subroutine calls, which is
    usually what an iterator needs. If you explain your actual need, it
    would help us answer your question better.

    Ted
    Ted Zlatanov, Feb 3, 2011
    #5
  6. George Mpouras

    Guest

    On Feb 1, 5:20 am, "George Mpouras"
    <> wrote:
    > At the following example I want to alter the value of $counter variable ,
    > but without using the the $iter code reference.
    > I 've tried many tricks using __ANON__ but without luck . Can you help ?
    >
    > my $iter = Create_counter(  37);
    >
    > for (1..3)
    > {
    > print "$_) ". $iter->() ."\n"
    > }
    >
    > sub Create_counter
    > {
    > my $counter = $_[0];
    >
    > return sub
    >   {
    >   $counter++
    >   }
    > }



    Dear George,

    The problem with trying to alter the $counter variable is that it
    is a variable that only gets modified inside the Create_counter()
    subroutine and the function it returns.

    Basically, you're using a closure. Read up on "perldoc -q closure"
    for a better idea of what a closure is.

    When you assign the subroutine reference to $iter with the line:

    my $iter = Create_counter(37);

    you're giving $iter the only power to modify the $counter variable
    that was created in the call to Create_counter() . From here on, the
    only way to modify that specific instance of $counter is to call $iter-
    >() .


    You can change all that if you modify the code, however. If you
    change the Create_counter() subroutine to look like:

    sub Create_counter
    {
    my $counter = $_[0];

    return \$counter, sub { $counter++ }
    }

    then you can call it like this:

    my ($counterRef, $iter) = Create_counter(37);

    and you can see and modify the value of the $counter by printing or
    assigning to $$counterRef (note the double '$' -- that's not a typo).
    What's more is that you can still call Create_counter() the old way,
    like this:

    my $iter = Create_counter(37);

    which will just discard the $counterRef part (due to assigning to a
    scalar). However, if you do this, then you lose the ability to
    observe and modify the $counter instance that $iter->() uses (other
    than just calling $iter->(), of course).

    If you prefer to avoid references, you can write Create_counter()
    this way:

    sub Create_counter
    {
    my $counter = $_[0];

    return sub { $counter }, # getter
    sub { $counter = $_[0] }, # setter
    sub { $counter++ } # iterator
    }

    This will allow you to write code like this:

    my ($getter, $setter, $iter) = Create_counter(37);

    print $iter->(); # prints 37 and sets $counter to 38
    print $getter->(); # prints out $counter, which is 38
    $setter->(5); # sets $counter to 5
    print $iter->(); # prints 5 and sets $counter to 6

    So if you want to be able to read/modify the $counter variable that
    $iter->() uses (without using $iter), you have to somehow return
    access to it, by either returning a reference to it, or by returning
    another sub { } that can read/modify it.

    I hope this helps, George.

    Have a great day!

    -- Jean-Luc
    , Feb 4, 2011
    #6
  7. George Mpouras

    Guest

    On Fri, 4 Feb 2011 11:04:01 -0800 (PST), "" <> wrote:

    >
    >
    >
    >
    >On Feb 1, 5:20 am, "George Mpouras"
    ><> wrote:
    >> At the following example I want to alter the value of $counter variable ,
    >> but without using the the $iter code reference.
    >> I 've tried many tricks using __ANON__ but without luck . Can you help ?
    >>
    >> my $iter = Create_counter(  37);
    >>
    >> for (1..3)
    >> {
    >> print "$_) ". $iter->() ."\n"
    >> }
    >>
    >> sub Create_counter
    >> {
    >> my $counter = $_[0];
    >>
    >> return sub
    >>   {
    >>   $counter++
    >>   }
    >> }

    >
    >
    >Dear George,
    >
    > The problem with trying to alter the $counter variable is that it
    >is a variable that only gets modified inside the Create_counter()
    >subroutine and the function it returns.
    >
    > Basically, you're using a closure. Read up on "perldoc -q closure"
    >for a better idea of what a closure is.
    >
    > When you assign the subroutine reference to $iter with the line:
    >
    > my $iter = Create_counter(37);
    >
    >you're giving $iter the only power to modify the $counter variable
    >that was created in the call to Create_counter() . From here on, the
    >only way to modify that specific instance of $counter is to call $iter-
    >>() .


    What about:

    return sub {
    if ($_[0]) {
    $counter = $_[0];
    } else {
      $counter++
    }

    then $iter->(0) and $iter->(),
    or is that too much out of range of the intended use of an itterator?

    -sln
    , Feb 4, 2011
    #7
  8. George Mpouras

    Guest

    On Feb 4, 4:17 pm, wrote:
    >
    > What about:
    >
    >  return sub {
    >           if ($_[0]) {
    >              $counter = $_[0];
    >           } else {
    >              $counter++
    >        }
    >
    > then $iter->(0) and  $iter->(),
    > or is that too much out of range of the intended use of an itterator?



    That would work for setting $counter -- but only to a non-zero
    value. (The way it is now, $iter->(0) will increment $counter.)

    As for peeking at the value of $counter (that is, reading it
    without modifying it), you might have to do this:

    print $iter->( $iter->() );

    but that might still increment the $counter, depending on when exactly
    the '++' operator decides to fire off. (I'm not sure if that's well
    defined in this case or not.)

    Cheers,

    -- Jean-Luc
    , Feb 5, 2011
    #8
  9. George Mpouras

    Guest

    On Fri, 4 Feb 2011 16:17:15 -0800 (PST), "" <> wrote:

    >On Feb 4, 4:17 pm, wrote:
    >>
    >> What about:
    >>
    >>  return sub {
    >>           if ($_[0]) {
    >>              $counter = $_[0];
    >>           } else {
    >>              $counter++
    >>        }
    >>
    >> then $iter->(0) and  $iter->(),
    >> or is that too much out of range of the intended use of an itterator?

    >
    >
    > That would work for setting $counter -- but only to a non-zero
    >value. (The way it is now, $iter->(0) will increment $counter.)
    >
    > As for peeking at the value of $counter (that is, reading it
    >without modifying it), you might have to do this:
    >
    > print $iter->( $iter->() );
    >
    >but that might still increment the $counter, depending on when exactly
    >the '++' operator decides to fire off. (I'm not sure if that's well
    >defined in this case or not.)
    >


    'if ($_[0])' I didn't see that foible.

    I guess poke and peak could be done
     return sub {
              if (defined $_[0]) {
                 $counter = $_[0];
              } else {
                 $counter++
           }
    print $iter->( $iter->() - 1 ); # but this isin't understandable

    or ---
     return sub {
              if (defined $_[0]) {
                 $counter = ($_[0] =~ /[a-zA-Z]/) ? $counter : $_[0];
              } else {
                 $counter++
           }
    print $iter->( 'getval' );
    print $iter->(0);

    As long as the itterator does its main function correctly,
    anything could be done in the sub, right?

    -sln
    , Feb 5, 2011
    #9
    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. Reporter
    Replies:
    3
    Views:
    470
    Mike Schilling
    May 12, 2007
  2. Tim Menninger

    Network File access using anonymous access

    Tim Menninger, Jul 22, 2004, in forum: ASP .Net Security
    Replies:
    2
    Views:
    183
    Raterus
    Jul 22, 2004
  3. Ronald Fischer

    "anonymous" variable in Perl?

    Ronald Fischer, Nov 30, 2004, in forum: Perl Misc
    Replies:
    10
    Views:
    500
    Anno Siegel
    Aug 9, 2005
  4. Replies:
    1
    Views:
    218
  5. Replies:
    29
    Views:
    197
Loading...

Share This Page