Re: Help with understanding references to subroutines

Discussion in 'Perl Misc' started by Peter J. Holzer, Jan 4, 2014.

  1. On 2014-01-04 19:40, Dave Stratford <> wrote:
    > Exercise
    >
    > Save the code below as call_subroutine_reference and where it says ###
    > insert code here ### get the subroutine reference from the arguments, run
    > it and store the returned value into $retval
    >
    > #!/usr/bin/perl
    >
    > use strict;
    > use warnings;
    > use Data::Dump 'pp';
    > use feature 'say';
    >
    > my $r_foo = sub { return "foo"; };
    > my $r_bar = sub { return {this => 1, that => 2}; };
    >
    > sub call_sub {
    >
    > ### Insert code here ###
    > # $retval is what the subroutine returns
    >
    > return $retval;
    > }
    >
    > say 'r_foo returns '.pp(call_sub($r_foo));
    > say 'r_bar returns '.pp(call_sub($r_bar));
    >
    >
    > The output should be:
    >
    > r_foo returns "foo"
    > r_bar returns { that => 2, this => 1 }
    >
    >========================== 8< ==========================
    >
    > From this I created the subroutine code as:
    >
    > sub call_sub {
    > my $data = shift;
    > my $retval;
    > if ($data == $r_foo)
    > {
    > $retval = &$r_foo;
    > }
    > else
    > {
    > $retval = &$r_bar;
    > }
    >
    > return $retval;
    > }
    >
    > When I run it, I get exactly what I want to get, but it seems to me to be
    > an excessively awkward way to decide which of two subroutines you want to
    > call.


    Yes, that's awkward, and missing the point.

    Let's simplify it a bit:

    > sub call_sub {
    > my $data = shift;
    > my $retval;
    > if ($data == $r_foo)
    > {
    > $retval = &$r_foo;


    Here $data == $r_foo, so we can replace this line with

    $retval = &$data;

    > }
    > else
    > {
    > $retval = &$r_bar;


    And here $data == $r_bar, so we can replace this line with

    $retval = &$data;

    > }
    >
    > return $retval;
    > }


    So, now both branches are identical and we can remove the if:

    sub call_sub {
    my $data = shift;
    my $retval;
    $retval = &$data;
    return $retval;
    }

    Looks a lot simpler, doesn't it? And also more general: call_sub() can
    now call ANY subroutine passed to it, not just $r_foo and $r_bar.


    > What is the purpose of the subroutine reference?


    I'm not sure if I understand the question. The purpose of subroutine
    references is to refer to subroutines, so that they can be stored in
    variables, passed as arguments to other functions, etc.


    > Why does call_sub even need to exist?


    To show you how to pass subroutine references around and how to call
    them. It's example code. It doesn't do anything useful.

    > I cannot see the purpose of passing a reference to a subroutine around,
    > why could the code not simply say:
    >
    > say 'r_foo returns '. &$r_foo;
    > say 'r_bar returns '. &$r_bar;


    You could do that. You could also use named subs and call those. But
    then there wouldn't be any references involved and it wouldn't be much
    use as an example.


    > After all, if you are calling call_sub($r_foo) then you must /know/ you
    > are calling r_foo.


    Yes, but only where you call call_sub(). The function call_sub() itself
    doesn't know anything about $r_foo. It just knows that it gets a
    subroutine reference which it is supposed to call.

    > I'm obviously missing something fairly fundamental here, so any help to
    > relieve the pressure on my poor suffering brain would be most appreciated.


    You are probably missing it because the example is so useless. In a real
    programm call_sub() would do something interesting, not just call a sub
    and return the result.

    For example, in the File::Find module, the find function recursively
    searches a directory tree and calls the function for every directory
    entry it finds. Or the builtin sort calls the comparison function for
    each pair of elements it wants to compare (it's just a block, not a sub,
    but that's just syntactic sugar).

    Being able to use a function reference in these cases is very useful:
    You don't have to rewrite directory walking code just because you want
    to do something different to the files it finds - just pass in a
    different "wanted" function. You don't have to rewrite sort just because
    you want to sort by different criteria - just pass in a different
    comparison function.

    > Any idea what IP chapter 7 might refer to?


    http://shop.oreilly.com/product/9780596102067.do I guess.

    > I was going to ask why Catalyst or Dancer would /require/ the use of
    > references to subroutines, but I think my brain already hurts enough as it
    > is.


    Because they need to call the functions you provide. It's very similar
    to what File::Find or sort do: They provide a framework, but you need to
    fill in the details.

    hp

    --
    _ | Peter J. Holzer | Fluch der elektronischen Textverarbeitung:
    |_|_) | | Man feilt solange an seinen Text um, bis
    | | | | die Satzbestandteile des Satzes nicht mehr
    __/ | http://www.hjp.at/ | zusammenpaßt. -- Ralph Babel
     
    Peter J. Holzer, Jan 4, 2014
    #1
    1. Advertising

  2. Ben Morrow <> writes:

    [...]

    > As Rainer pointed out, the &-form for calling subs can have
    > side-effects; in the particular case of calling through a reference,
    > prototypes don't apply, but if you write the call as
    >
    > $retval = &$data;
    >
    > rather than
    >
    > $retval = &$data();
    >
    > $data will inherit the current @_, which is obviously a Bad Thing.


    I beg to differ here: Accidentally writing code whith this property is
    very likely a 'Bad Thing', however, the feature itself is quite useful
    for building subroutine processing pipelines where each individual sub
    performs 'some subtask of something' which possibly involves modifying
    @_ and then 'passes the buck' to another subroutine withg &-call.
     
    Rainer Weikusat, Jan 7, 2014
    #2
    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. ReaprZero

    References and subroutines

    ReaprZero, Dec 4, 2003, in forum: Perl
    Replies:
    1
    Views:
    463
    Gunnar Hjalmarsson
    Dec 4, 2003
  2. Ketema

    References Subroutines and Arrays

    Ketema, Mar 5, 2004, in forum: Perl Misc
    Replies:
    2
    Views:
    153
  3. Rainer Weikusat
    Replies:
    1
    Views:
    150
    Rainer Weikusat
    Jan 4, 2014
  4. Jürgen Exner
    Replies:
    9
    Views:
    119
    Charlton Wilbur
    Jan 13, 2014
  5. George Mpouras
    Replies:
    0
    Views:
    83
    George Mpouras
    Jan 5, 2014
Loading...

Share This Page