Very basic question on using references inside functions

Discussion in 'Perl Misc' started by Mark Seger, Aug 15, 2005.

  1. Mark Seger

    Mark Seger Guest

    I'd have thought this would have been answered in some of the
    documentation on using references but if it was I missed it.

    I understand that if I want to call a function and pass it a reference
    to a scalar I can then modify that scalar within the function as follows:

    sub foo {
    my $ref=shift;
    $$ref='new value';
    }

    and it works just fine. However, I want to use that scalar within the
    function many times and don't want to call it $$ref every time because
    it feels clumsy.

    Is there some other way? I thought I could make a reference to that
    reference by something like $var=\$$ref and just access $var but that
    didn't work. My REAL motive for asking is I have some code that passes
    parameters by value and I'd like to go back and pass them by reference
    without have to change all the other code that touches them.

    Then again, maybe the perlish way to do it IS to refer to them
    everywhere as $$ref, $@ref or %$ref just to be clearer about what it
    really going on.

    -mark
     
    Mark Seger, Aug 15, 2005
    #1
    1. Advertising

  2. Mark Seger

    Anno Siegel Guest

    Mark Seger <> wrote in comp.lang.perl.misc:
    > I'd have thought this would have been answered in some of the
    > documentation on using references but if it was I missed it.
    >
    > I understand that if I want to call a function and pass it a reference
    > to a scalar I can then modify that scalar within the function as follows:
    >
    > sub foo {
    > my $ref=shift;
    > $$ref='new value';
    > }
    >
    > and it works just fine. However, I want to use that scalar within the
    > function many times and don't want to call it $$ref every time because
    > it feels clumsy.


    It's how it's done, clumsy or not.

    > Is there some other way? I thought I could make a reference to that
    > reference by something like $var=\$$ref and just access $var but that
    > didn't work.


    That would give you an additional layer of reference and make the
    access more complicated, not less.

    > My REAL motive for asking is I have some code that passes
    > parameters by value and I'd like to go back and pass them by reference
    > without have to change all the other code that touches them.


    Perl *does* pass scalars "by reference" in the sense that a parameter
    value can be changed from within the function. Example:

    sub foe {
    $_[ 0] = 'new value';
    }
    my $x = 'old value';
    fum( $x);
    print "$x\n";

    If you want to access the variable under a meaningful name (instead of
    $_[ 0]) you can use a one-shot for loop to get an alias (this is also
    called topicalization):

    sub fum {
    for my $variable ( $_[ 0] ) {
    $variable = 'new value';
    }
    }

    So references are not really necessary to change a scalar variable
    from within a sub. (Aggregates are a different matter.) However,
    a code change will be necessary either way.

    Anno
    --
    If you want to post a followup via groups.google.com, don't use
    the broken "Reply" link at the bottom of the article. Click on
    "show options" at the top of the article, then click on the
    "Reply" at the bottom of the article headers.
     
    Anno Siegel, Aug 15, 2005
    #2
    1. Advertising

  3. Mark Seger wrote:
    > I understand that if I want to call a function and pass it a reference
    > to a scalar I can then modify that scalar within the function as follows:
    >
    > sub foo {
    > my $ref=shift;
    > $$ref='new value';
    > }
    >
    > and it works just fine. However, I want to use that scalar within the
    > function many times and don't want to call it $$ref every time because
    > it feels clumsy.


    <snip>

    > My REAL motive for asking is I have some code that passes
    > parameters by value and I'd like to go back and pass them by reference
    > without have to change all the other code that touches them.


    So you don't care whether the passed variable is changed? In that case,
    there is of course the obvious dereference way:

    sub foo {
    my $var = ${ $_[0] };
    $var = 'new value';
    }

    OTOH, then you wouldn't gain much from passing references instead of
    values...

    --
    Gunnar Hjalmarsson
    Email: http://www.gunnar.cc/cgi-bin/contact.pl
     
    Gunnar Hjalmarsson, Aug 15, 2005
    #3
  4. Mark Seger

    Mark Seger Guest


    > Perl *does* pass scalars "by reference" in the sense that a parameter
    > value can be changed from within the function. Example:
    >
    > sub foe {
    > $_[ 0] = 'new value';
    > }
    > my $x = 'old value';
    > fum( $x);
    > print "$x\n";
    >

    What I meant by 'pass by reference' is that any changes you make in the
    function are reflected back at caller who will then see changes to that
    parameter. I believe what perl does is 'pass by value', in that it
    makes a copy of the data, thereby allowing you to change it without fear
    of clobbering the orignal value.

    > If you want to access the variable under a meaningful name (instead of
    > $_[ 0]) you can use a one-shot for loop to get an alias (this is also
    > called topicalization):
    >
    > sub fum {
    > for my $variable ( $_[ 0] ) {
    > $variable = 'new value';
    > }
    >

    }
    I do this all the time for all variables, even in for loops as I find
    references like @_ or $_ read very poorly, but that's me.

    -mark
     
    Mark Seger, Aug 15, 2005
    #4
  5. Mark Seger

    Anno Siegel Guest

    Mark Seger <> wrote in comp.lang.perl.misc:
    >
    > > Perl *does* pass scalars "by reference" in the sense that a parameter
    > > value can be changed from within the function. Example:
    > >
    > > sub foe {
    > > $_[ 0] = 'new value';
    > > }
    > > my $x = 'old value';
    > > fum( $x);
    > > print "$x\n";
    > >

    > What I meant by 'pass by reference' is that any changes you make in the
    > function are reflected back at caller who will then see changes to that
    > parameter. I believe what perl does is 'pass by value', in that it
    > makes a copy of the data, thereby allowing you to change it without fear
    > of clobbering the orignal value.


    You believe wrong. The code example above shows that changes to sub
    arguments (the elements of @_) are indeed visible to the caller. The
    "call-by-value" thing happens when you assign the content of @_ to
    local variables, as in "my ( $x, $y, $z) = @_;". If you change $x etc.
    in the sub body, nothing is changed in the environment. If you change
    $_[ 0] etc. directly, it is.

    > > If you want to access the variable under a meaningful name (instead of
    > > $_[ 0]) you can use a one-shot for loop to get an alias (this is also
    > > called topicalization):
    > >
    > > sub fum {
    > > for my $variable ( $_[ 0] ) {
    > > $variable = 'new value';
    > > }
    > >

    > }
    > I do this all the time for all variables, even in for loops as I find
    > references like @_ or $_ read very poorly, but that's me.


    That's an unrelated point. The aliasing behavior of "for" is the same
    whether you use an explicit variable or the default $_.

    sub fum {
    for ( $_[ 0] ) {
    $_ = 'new value';
    }
    }

    would have illustrated my point just as well.

    Anno
    --
    If you want to post a followup via groups.google.com, don't use
    the broken "Reply" link at the bottom of the article. Click on
    "show options" at the top of the article, then click on the
    "Reply" at the bottom of the article headers.
     
    Anno Siegel, Aug 15, 2005
    #5
  6. Mark Seger

    Guest

    Mark Seger <> wrote:
    > I'd have thought this would have been answered in some of the
    > documentation on using references but if it was I missed it.
    >
    > I understand that if I want to call a function and pass it a reference
    > to a scalar I can then modify that scalar within the function as follows:
    >
    > sub foo {
    > my $ref=shift;
    > $$ref='new value';
    > }
    >
    > and it works just fine. However, I want to use that scalar within the
    > function many times and don't want to call it $$ref every time because
    > it feels clumsy.


    Tough it out. It stops feeling clumsy after a while.

    > Is there some other way? I thought I could make a reference to that
    > reference by something like $var=\$$ref and just access $var but that
    > didn't work.


    That is effectively the same thing as $var=$ref; It doesn't change the way
    you dereference it.


    > My REAL motive for asking is I have some code that passes
    > parameters by value and I'd like to go back and pass them by reference
    > without have to change all the other code that touches them.


    If it currently passes parameters (effectively) by value, and it does the
    right thing, then wouldn't changing it to pass them by reference cause it
    to do the wrong thing unless you change all that other code anyway?

    You could use typeglobs (or whatever it is I am supposed to call those
    things). I don't particularly recommend it, but I have used it in a pinch.

    use strict;

    my $x='j' x 10;

    print "$x\n";
    foo3($x);
    print "$x\n";

    sub foo3 {
    our $y;
    *y = \$_[0];
    $y =~ s/j/k/g;
    };

    Xho

    --
    -------------------- http://NewsReader.Com/ --------------------
    Usenet Newsgroup Service $9.95/Month 30GB
     
    , Aug 15, 2005
    #6
  7. Mark Seger

    Anno Siegel Guest

    <> wrote in comp.lang.perl.misc:
    > Mark Seger <> wrote:


    [variable passing]

    > You could use typeglobs (or whatever it is I am supposed to call those
    > things). I don't particularly recommend it, but I have used it in a pinch.
    >
    > use strict;
    >
    > my $x='j' x 10;
    >
    > print "$x\n";
    > foo3($x);
    > print "$x\n";
    >
    > sub foo3 {
    > our $y;
    > *y = \$_[0];
    > $y =~ s/j/k/g;
    > };


    Yes, but why?

    sub foo4 { $_[ 0] =~ s/j/k/g }

    or

    sub foo5 { s/j/k/g for shift }

    do the same thing directly.

    Anno
    --
    If you want to post a followup via groups.google.com, don't use
    the broken "Reply" link at the bottom of the article. Click on
    "show options" at the top of the article, then click on the
    "Reply" at the bottom of the article headers.
     
    Anno Siegel, Aug 15, 2005
    #7
  8. Mark Seger

    Guest

    -berlin.de (Anno Siegel) wrote:
    > <> wrote in comp.lang.perl.misc:
    > > Mark Seger <> wrote:

    >
    > [variable passing]
    >
    > > You could use typeglobs (or whatever it is I am supposed to call those
    > > things). I don't particularly recommend it, but I have used it in a
    > > pinch.
    > >
    > > use strict;
    > >
    > > my $x='j' x 10;
    > >
    > > print "$x\n";
    > > foo3($x);
    > > print "$x\n";
    > >
    > > sub foo3 {
    > > our $y;
    > > *y = \$_[0];
    > > $y =~ s/j/k/g;
    > > };

    >
    > Yes, but why?


    The point of a short but complete example script (like people here are
    always asking for) is to show how something is done. It is not to show why
    it is done. The why is covered in the prose. I thought it was pretty
    obvious why to do that.
    >
    > sub foo4 { $_[ 0] =~ s/j/k/g }


    unlike $_[0], the name of $y can be arbitrarily chosen. If you are going
    to use the variable fifty times in your subroutine, that is quite a
    benefit.

    Xho

    --
    -------------------- http://NewsReader.Com/ --------------------
    Usenet Newsgroup Service $9.95/Month 30GB
     
    , Aug 16, 2005
    #8
  9. Mark Seger

    Anno Siegel Guest

    <> wrote in comp.lang.perl.misc:
    > -berlin.de (Anno Siegel) wrote:
    > > <> wrote in comp.lang.perl.misc:
    > > > Mark Seger <> wrote:

    > >
    > > [variable passing]
    > >
    > > > You could use typeglobs (or whatever it is I am supposed to call those
    > > > things). I don't particularly recommend it, but I have used it in a
    > > > pinch.
    > > >
    > > > use strict;
    > > >
    > > > my $x='j' x 10;
    > > >
    > > > print "$x\n";
    > > > foo3($x);
    > > > print "$x\n";
    > > >
    > > > sub foo3 {
    > > > our $y;
    > > > *y = \$_[0];
    > > > $y =~ s/j/k/g;
    > > > };

    > >
    > > Yes, but why?

    >
    > The point of a short but complete example script (like people here are
    > always asking for) is to show how something is done. It is not to show why
    > it is done. The why is covered in the prose. I thought it was pretty
    > obvious why to do that.


    You say "in a pinch", but I don't see the pinch that makes a solution
    involving package variables attractive.

    > > sub foo4 { $_[ 0] =~ s/j/k/g }

    >
    > unlike $_[0], the name of $y can be arbitrarily chosen. If you are going
    > to use the variable fifty times in your subroutine, that is quite a
    > benefit.


    You can have that lexically too:

    for my $y ( shift ) {
    $y =~ s/j/k/g;
    }

    (Admitted, it doesn't scale well for more than one variable.)

    You know the reason to avoid package variables: exposure. If you have
    a rogue function do_something() (say, imported from somewhere), which does

    sub do_something {
    # ....
    our $y = 'something else';
    }

    then calling do_something() while "*y = \ $_[ 0]" is in effect has
    unexpected and hard-to-trace consequences:

    sub foo6 {
    our $y;
    *y = \ shift();
    do_something()
    $y =~ s/g/k/g;
    }

    now sets its argument to "somethink else".

    Anno
    --
    If you want to post a followup via groups.google.com, don't use
    the broken "Reply" link at the bottom of the article. Click on
    "show options" at the top of the article, then click on the
    "Reply" at the bottom of the article headers.
     
    Anno Siegel, Aug 16, 2005
    #9
  10. Mark Seger

    Mark Seger Guest

    Anno Siegel wrote:
    > Mark Seger <> wrote in comp.lang.perl.misc:
    >
    >>>Perl *does* pass scalars "by reference" in the sense that a parameter
    >>>value can be changed from within the function. Example:
    >>>
    >>> sub foe {
    >>> $_[ 0] = 'new value';
    >>> }
    >>> my $x = 'old value';
    >>> fum( $x);
    >>> print "$x\n";
    >>>

    >>
    >>What I meant by 'pass by reference' is that any changes you make in the
    >>function are reflected back at caller who will then see changes to that
    >>parameter. I believe what perl does is 'pass by value', in that it
    >>makes a copy of the data, thereby allowing you to change it without fear
    >>of clobbering the orignal value.

    >
    >
    > You believe wrong. The code example above shows that changes to sub
    > arguments (the elements of @_) are indeed visible to the caller. The
    > "call-by-value" thing happens when you assign the content of @_ to
    > local variables, as in "my ( $x, $y, $z) = @_;". If you change $x etc.
    > in the sub body, nothing is changed in the environment. If you change
    > $_[ 0] etc. directly, it is.


    yikes! I was indeed wrong. I guess my habit of ALWAYS saying
    my $xyz=shift
    for each parameter has protected me in my ignorance. :cool:

    but from yours and other notes I think I'll be a lot more comfortable
    with passing references around now.

    -mark
     
    Mark Seger, Aug 16, 2005
    #10
  11. Mark Seger

    Guest

    -berlin.de (Anno Siegel) wrote:
    > <> wrote in comp.lang.perl.misc:
    > > -berlin.de (Anno Siegel) wrote:
    > > > >
    > > > > sub foo3 {
    > > > > our $y;
    > > > > *y = \$_[0];
    > > > > $y =~ s/j/k/g;
    > > > > };
    > > >
    > > > Yes, but why?

    > >
    > > The point of a short but complete example script (like people here are
    > > always asking for) is to show how something is done. It is not to show
    > > why it is done. The why is covered in the prose. I thought it was
    > > pretty obvious why to do that.

    >
    > You say "in a pinch", but I don't see the pinch that makes a solution
    > involving package variables attractive.


    It wasn't attractive. Just better than the alternatives I could think of.
    We desperately needed to refactor the code. But we even more desperately
    needed an answer which couldn't wait until the refactoring was done.

    >
    > > > sub foo4 { $_[ 0] =~ s/j/k/g }

    > >
    > > unlike $_[0], the name of $y can be arbitrarily chosen. If you are
    > > going to use the variable fifty times in your subroutine, that is quite
    > > a benefit.

    >
    > You can have that lexically too:
    >
    > for my $y ( shift ) {
    > $y =~ s/j/k/g;
    > }
    >
    > (Admitted, it doesn't scale well for more than one variable.)


    And that was exactly the pinch that spurred me to use typeglobs[1].

    Although I guess I could have used

    foreach my $x (shift) {
    foreach my $y (shift) {
    foreach my $z (shift) {
    foreach my $w (shift) {
    foreach my $q (shift) {
    .....
    }}}}}

    Which is not that much uglier than the typeglobs, and definitely cleaner
    from a "symbolic reference like things are evil" POV. (BTW, before someone
    asks, I didn't indent the above on purpose. Since I want all the foreachs
    together to act essentially as one atomic aliasing operation, I want them
    all indented together. I would have put them all on one line, but that
    would be too long. Besides, if I am using foreach to do something out of
    the ordinary, it deserves to look out of the ordinary.)


    [1] Ok, maybe not exactly. Looking back at that actual code, there was one
    more factor involved.

    my @x=1..20;
    print "@x\n";
    foo6($foo,$bar,\@x,$baz,$and,\@many,$more);
    print "@x\n";

    sub foo6 {
    our @fooarray;
    *fooarray=$_[2];
    @fooarray=reverse @fooarray; # legacy code.
    };

    Where the 'reverse' line is standing in for >1500 lines that use @fooarray
    several hundred times, plus several similarly situated other variables.

    That one I still don't know a quick non-typeglob solution to (other than
    refusing to take over crappy code from other people. But then they would
    probably refuse to pay me, which would make me sad.)

    Xho

    --
    -------------------- http://NewsReader.Com/ --------------------
    Usenet Newsgroup Service $9.95/Month 30GB
     
    , Aug 16, 2005
    #11
  12. Mark Seger

    Anno Siegel Guest

    <> wrote in comp.lang.perl.misc:
    > -berlin.de (Anno Siegel) wrote:
    > > <> wrote in comp.lang.perl.misc:
    > > > -berlin.de (Anno Siegel) wrote:
    > > > > >
    > > > > > sub foo3 {
    > > > > > our $y;
    > > > > > *y = \$_[0];
    > > > > > $y =~ s/j/k/g;
    > > > > > };
    > > > >
    > > > > Yes, but why?


    [...]

    > > You can have that lexically too:
    > >
    > > for my $y ( shift ) {
    > > $y =~ s/j/k/g;
    > > }
    > >
    > > (Admitted, it doesn't scale well for more than one variable.)

    >
    > And that was exactly the pinch that spurred me to use typeglobs[1].


    Ah, I see.

    > Although I guess I could have used
    >
    > foreach my $x (shift) {
    > foreach my $y (shift) {
    > foreach my $z (shift) {
    > foreach my $w (shift) {
    > foreach my $q (shift) {
    > ....
    > }}}}}
    >
    > Which is not that much uglier than the typeglobs, and definitely cleaner
    > from a "symbolic reference like things are evil" POV. (BTW, before someone

    ^^^^^^^^^^^^^^^^^^
    Just package variables. I don't think they are evil, sometimes their
    program-wide scope is just what is needed. Still the rule is that scopes
    should be as small as possible.

    > asks, I didn't indent the above on purpose. Since I want all the foreachs
    > together to act essentially as one atomic aliasing operation, I want them
    > all indented together. I would have put them all on one line, but that
    > would be too long. Besides, if I am using foreach to do something out of
    > the ordinary, it deserves to look out of the ordinary.)


    It's a perfectly reasonable way to write this bit of code, imo. The nesting
    of blocks that indentation would draw attention to is an artifact, we have
    no other way to express this in Perl. If there was syntax for walking
    through multiple lists in parallel, we'd use that with a single level.

    > [1] Ok, maybe not exactly. Looking back at that actual code, there was one
    > more factor involved.
    >
    > my @x=1..20;
    > print "@x\n";
    > foo6($foo,$bar,\@x,$baz,$and,\@many,$more);
    > print "@x\n";
    >
    > sub foo6 {
    > our @fooarray;
    > *fooarray=$_[2];
    > @fooarray=reverse @fooarray; # legacy code.
    > };
    >
    > Where the 'reverse' line is standing in for >1500 lines that use @fooarray
    > several hundred times, plus several similarly situated other variables.


    ....which used to be globals and had to be shoehorned into the parameter
    list post factum, am I right?

    > That one I still don't know a quick non-typeglob solution to (other than


    One could tie @fooarray appropriately (Brian's Tie::OneOff would make that
    a snap), but that might scare your co-workers. Well, if they said it was
    over-engineering they might be right.

    With the typeglob solution, your variables are still globals, (just
    controlled locally, which is also a gain), so you have come only part
    of the way if elimination of globals was indeed the purpose.

    After this discussion I'd use the nested for-loops where applicable,
    particularly after you invented such a nice format for it. About
    those arrays (and similarly used hashes) I don't know. I'd have
    to code up a tie-solution to imagine how it looks in context, but
    not now.

    Anno
    --
    If you want to post a followup via groups.google.com, don't use
    the broken "Reply" link at the bottom of the article. Click on
    "show options" at the top of the article, then click on the
    "Reply" at the bottom of the article headers.
     
    Anno Siegel, Aug 16, 2005
    #12
  13. Anno Siegel wrote:

    > You know the reason to avoid package variables: exposure.


    I think this is often over-played. Perl allows you to play about with
    package variables in other packages just as it lets you fiddle with the
    internal of objects. But it's fairly obvious when you are doing it.

    > If you have
    > a rogue function do_something() (say, imported from somewhere), which does
    >
    > sub do_something {
    > # ....
    > our $y = 'something else';
    > }


    If this was imported from elsewhere it would be talking about a $y in a
    different package so there would be no problem. If it's not imported
    and is defined within the same module then it's just the usual problem
    of managing global variables. (Note when I say 'global' I don't mean
    'package', I mean 'package or file-scoped lexical'). This is why you
    should always minimize your use of global variables. But sometimes they
    are the right tool for the job.

    > then calling do_something() while "*y = \ $_[ 0]" is in effect has
    > unexpected and hard-to-trace consequences:
    >
    > sub foo6 {
    > our $y;
    > *y = \ shift();
    > do_something()
    > $y =~ s/g/k/g;
    > }


    If you are going to use package variables it's wise to get into the
    habit of using local().

    That said I would _not_ use typeglobs for this reason - I'd use one of
    the other approaches given in this thead.
     
    Brian McCauley, Aug 20, 2005
    #13
    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. Raymond Arthur St. Marie II of III

    very Very VERY dumb Question About The new Set( ) 's

    Raymond Arthur St. Marie II of III, Jul 23, 2003, in forum: Python
    Replies:
    4
    Views:
    524
    Raymond Hettinger
    Jul 27, 2003
  2. aghazalp

    very very basic question

    aghazalp, Apr 2, 2006, in forum: Python
    Replies:
    6
    Views:
    357
    aghazalp
    Apr 2, 2006
  3. shanx__=|;-

    very very very long integer

    shanx__=|;-, Oct 16, 2004, in forum: C Programming
    Replies:
    19
    Views:
    1,727
    Merrill & Michele
    Oct 19, 2004
  4. Peter

    Very very very basic question

    Peter, Feb 8, 2005, in forum: C Programming
    Replies:
    14
    Views:
    547
    Dave Thompson
    Feb 14, 2005
  5. mdh

    A very **very** basic question

    mdh, Sep 25, 2008, in forum: C Programming
    Replies:
    57
    Views:
    1,285
    August Karlstrom
    Sep 26, 2008
Loading...

Share This Page