Re: Help with understanding references to subroutines

Discussion in 'Perl Misc' started by Jürgen Exner, Jan 5, 2014.

  1. Dave Stratford <> wrote:
    [...]
    >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.


    In that contrived example, yes.

    >What is the purpose of the subroutine reference?
    >Why does call_sub even need to exist?
    >I cannot see the purpose of passing a reference to a subroutine around,
    >
    >After all, if you are calling call_sub($r_foo) then you must /know/ you
    >are calling r_foo.
    >
    >Even, why have them as references to anonymous subroutines in the first
    >place?
    >
    >I'm obviously missing something fairly fundamental here, so any help to
    >relieve the pressure on my poor suffering brain would be most appreciated.


    Your are right, for simple examples references to functions are rarely
    all that useful. However they begin to make a lot of sense as soon as
    you are starting to talk about higher order functions, i.e. functions
    that take functions as arguments. They are extremely powerful although
    many developers never understand them. Some examples (free-style
    notation):

    filter (aka grep): takes a list of items and a custom function which
    returns true or false for each item of the list; returns the list of
    items for which the custom function yields true.

    map: takes a list of items and a custom function; this function is
    applied to each item in the list

    reduce: takes a list of items L and custom function OP; then this
    operation is applied between all items of the list until only a single
    element is left
    L[0] OP L[1] OP L[2] OP L[3] ..... L[n]
    If OP happens be + then you get the sum of all elements, if it is * then
    you get the product of all elements, if it is a custom function
    returning the larger of both arguments then you get the maximum value of
    the list, etc, etc.

    sort: takes a list of items and a custom function which for any two
    items decides if the left item or the right item is larger or if both
    are equal.

    The beauty of these HOFs is that they don't care about the type of item.
    They are generic and will work on lists of numbers, lists of strings,
    lists of personel records, lists of whatever, because the handling of
    the actual item is left to the custom function which is user-supplied as
    an argument. And therefore I don't need to implement 5 dozen sort
    functions only because I need to sort lists of 5 dozen different item
    types.

    jue
     
    Jürgen Exner, Jan 5, 2014
    #1
    1. Advertising

  2. Dave Stratford <> writes:
    > In article <>,
    > Jürgen Exner <> wrote:
    >> Dave Stratford <> wrote:
    >> [...]
    >> >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.

    >
    >> In that contrived example, yes.

    >
    > <snip>
    >
    > Thanks for all the help and advice guys. I'm still not 100% sure I
    > understand it enough, but at least I do know that there is a reason.


    I can also provide you with a simple, real example although I can't
    quote the code since it belongs to my employer: I'm presently working on
    a mod_perl-based 'web application' (in the sense that it is supposed to
    work in response to a HTTP GET request) which is supposed to create
    PDF-documents containing QR-code images supposed to be used for
    interacting with another web application. Creating these images requires
    connecting to a database server and querying various pieces of
    information from it, possibly, a lot of pieces (tenthousands). Since
    this will be an autonomously operating piece of software, it needs to be
    able to deal with database connections suddenly breaking down, ie,
    because the DBMS was restarted as part of a system update. The way this
    works is as follows:

    There's a low-level database interface layer which executes queries on
    behalf of the application. In case of database errors, these are
    classified as either irrecoverable or transient and an exception is
    thrown (via die) containing information about the error and its type.

    Then, there's a mid-level 'execution' layer which takes a reference to a
    subroutine as argument. This subroutine is supposed to perform the
    actual application work. All of its state information is to be stored in
    my-variables created by it and any other subroutines it might need to
    call. The executor invokes this subroutine in an eval block and catches
    exceptions thrown by the database interface layer. In case the error is
    considered to be recoverable, it kills the database connection (if it
    still exists), destroys the (DBI) database handle object, waits for a
    random, short time and starts over.

    The 'application subroutines' (there's actually more than one)
    themselves just perform their work without any concern for problems
    which could occur while interacting with the database.

    Note to the '"Download stuff from the internet!"-autoresponder': The
    total size of this is 132 lines of code. The fact that some
    CPAN-codeblob with presumably more than 100 times this size exists which
    hopefully(!) provides this as an also-feature among the toaster,
    lawnmower, hovercraft, big game trap, mail reader, howitzer and
    pencil-sharpener also rolled into it is not an excuse for using that.
     
    Rainer Weikusat, Jan 8, 2014
    #2
    1. Advertising

  3. Ben Morrow <> writes:
    > Quoth Rainer Weikusat <>:
    >>
    >> Note to the '"Download stuff from the internet!"-autoresponder': The
    >> total size of this is 132 lines of code. The fact that some
    >> CPAN-codeblob with presumably more than 100 times this size exists which
    >> hopefully(!) provides this as an also-feature among the toaster,
    >> lawnmower, hovercraft, big game trap, mail reader, howitzer and
    >> pencil-sharpener also rolled into it is not an excuse for using that.

    >
    > Oh, do shut up.


    Again, an argument in favour of "Whatever J. Random Bored Guy
    uploaded to J. Random Software Rubbish Dump" must be used because it was
    uploaded, regardless of any non-desirable properties it might have,
    would be most welcome.
     
    Rainer Weikusat, Jan 8, 2014
    #3
  4. Ben Morrow <> writes:
    > Quoth Rainer Weikusat <>:
    >> Ben Morrow <> writes:
    >> > Quoth Rainer Weikusat <>:
    >> >>
    >> >> Note to the '"Download stuff from the internet!"-autoresponder': The
    >> >> total size of this is 132 lines of code. The fact that some
    >> >> CPAN-codeblob with presumably more than 100 times this size exists which
    >> >> hopefully(!) provides this as an also-feature among the toaster,
    >> >> lawnmower, hovercraft, big game trap, mail reader, howitzer and
    >> >> pencil-sharpener also rolled into it is not an excuse for using that.
    >> >
    >> > Oh, do shut up.

    >>
    >> Again, an argument in favour of "Whatever J. Random Bored Guy
    >> uploaded to J. Random Software Rubbish Dump" must be used because it was
    >> uploaded, regardless of any non-desirable properties it might have,
    >> would be most welcome.

    >
    > Oh, do shut up.


    http://en.wikipedia.org/wiki/Sturgeon's_Law

    There are

    - some CPAN modules I use because they provide functionality
    orthogonal to 'the core of the application' which is also
    needed but I don't desire to deal with it in more detail
    except if there's a critical bug in the module

    - some CPAN modules I use because they saved me a significant
    amount of work despite they're earmarked for replacement
    because of known deficiencies should time permit

    - some CPAN modules I use because I consider them 'generally
    well-designed and useful' for the purpose at hand, possibly
    extended with features I happen to need the module author(s)
    were less interested in

    - some CPAN modules I wouldn't touch with a ten feet barge
    pole, generalized event loops, kitchen sink abstractions
    solving wildly differing problems, OO systems of any pedigree
    (if I though the Perl OO system was seriously unusable, I
    wouldn't be using Perl) and generally (or mostly) everything
    which is supposed to solve 'programming problems' instead of
    'real problems'

    YMMV.
     
    Rainer Weikusat, Jan 8, 2014
    #4
  5. Jürgen Exner

    Uri Guttman Guest

    >>>>> "DS" == Dave Stratford <> writes:

    DS> Thanks for all the help and advice guys. I'm still not 100% sure I
    DS> understand it enough, but at least I do know that there is a reason.

    it is much simpler than you realize. it is just a mindset change that
    you need to make.

    it is just that code can be treated like data (lisp is all about
    that). so you can put code into data structures, pass code as arguments,
    etc. a very common use of code refs is a dispatch table. it is a hash of
    keys but the values are code references. this way you can choose which
    sub to call based on some key. i am sure there are plenty of perl
    examples all over usenet and beyond.

    so a sub reference is just a scalar value that refers to a sub and which
    can then be called. it can be created from a named sub or by an
    anonymous sub (just like with named or anon hashes and arrays).

    an example of a sub as an argument would be choosing different ways to
    output something. the sub could be printing to a file, logging, etc. the
    main sub is passed its args and a sub to control output. when it has
    output it calls that sub and passes it stuff to output.

    this is also called polymophism. each of the subs you can pass in must
    (should) have the same api. that way the main sub doesn't have to do
    anything special but use the single section of code to call the sub
    ref. same with the above dispatch table. all of the subs in it should
    take the same args and return the same type of value (if they return
    something).

    so think of sub refs as an elegant and efficient way to choose something
    at a distance. instead of a long ugly if/then/else block you just need
    to choose the correct sub (from the dispatch table or via passing it in
    as an arg). like most software tricks it isn't NEEDED but very useful
    and popular. but then again, most software things are just sugar over
    assembler too. :)

    uri
     
    Uri Guttman, Jan 8, 2014
    #5
  6. Jürgen Exner

    Tim McDaniel Guest

    In article <>,
    Dave Stratford <> wrote:
    >At some point you
    >are having to decide which function to call, so why do you then need refs?
    >Couldn't you just call the function?


    That's like saying "Why do you need refs/pointers/subscripts?
    Couldn't you just set the variable itself?" That's practially like
    advocating

    if ($i == 1) {
    $a1 = $x;
    } elsif ($i == 2) {
    $a2 = $x;
    } elsif ($i == 3) {
    $a3 = $x;
    ...

    and not realizing that there's a problem with using a value that's not
    hardcoded (what if you implement $a1 through $a100 and then need
    $a101?), and professing not to see any use for

    $a[$i] = $x;

    >Sorry if this sounds a bit basic, but having programmed in a large
    >number of different, occasionally esoteric, languages for just over
    >30 years, I can't think of an instance where this has even been
    >possible before.


    Haven't you ever used Perl's sort, map, or grep? I'm told they are
    not quite sub references, but they look enough like them to be a
    useful mental model for me. How about $SIG{...}? You give them sub
    references.

    What languages have you used?

    In C, they're function pointers. In standard libraries, they are used in
    atexit: register a function to be called at program exit (like
    Perl's $SIG{__DIE__}, I think)
    bsearch, qsort: search and sort don't know the datatypes of what
    they're sorting, so you pass in a comparison function
    signal: register a signal handler function (%SIG)

    In Fortran, they are EXTERNAL arguments. I used them in math -- for
    example, you have a Runge-Kutta solver but you need to pass it a
    function that you're trying to integrate.

    In Java, I think they tend to use interfaces, so I think you create a
    class that implements the interface, and in that class have a method
    with the standard name that does what you want. You're not passing a
    pointer to a method -- but you are passing a pointer to an object that
    happens to call the particular method you want to run.

    --
    Tim McDaniel,
     
    Tim McDaniel, Jan 9, 2014
    #6
  7. Dave Stratford <> writes:
    > In article <>,
    > Rainer Weikusat <> wrote:
    >> Dave Stratford <> writes:
    >> > In article <>,
    >> > Jürgen Exner <> wrote:
    >> >> Dave Stratford <> wrote:
    >> >> [...]
    >> >> >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.
    >> >
    >> >> In that contrived example, yes.
    >> >
    >> > <snip>
    >> >
    >> > Thanks for all the help and advice guys. I'm still not 100% sure I
    >> > understand it enough, but at least I do know that there is a reason.

    >
    >> I can also provide you with a simple, real example although I can't
    >> quote the code since it belongs to my employer:

    >
    > <snip code description>
    >
    > That all sounds genuinely fascinating, especially the bit about creating
    > QR codes; but from your descripton, granted it's only a fairly high level
    > description, but are function refs actually necessary? At some point you
    > are having to decide which function to call, so why do you then need refs?
    > Couldn't you just call the function?


    Please consider this:

    ,----
    | Then, there's a mid-level 'execution' layer which takes a reference to a
    | subroutine as argument. This subroutine is supposed to perform the
    | actual application work. All of its state information is to be stored in
    | my-variables created by it and any other subroutines it might need to
    | call. The executor invokes this subroutine in an eval block and catches
    | exceptions thrown by the database interface layer. In case the error is
    | considered to be recoverable, it kills the database connection (if it
    | still exists), destroys the (DBI) database handle object, waits for a
    | random, short time and starts over.
    `----

    A contrived mockup of that could look like this:

    ----------
    sub operation() {
    die("Shit happened\n") if rand(10) <= 7;
    return rand(12);
    }

    sub execute
    {
    my $sub = $_[0];
    my $rc;

    {
    eval {
    $rc = $sub->();
    };

    $@ and do {
    print STDERR ("\t** $@");
    redo;
    };
    }

    return $rc;
    }

    sub random_add
    {
    return operation() + 12;
    }

    sub random_sub
    {
    return operation() - 3;
    }

    printf("random add returned %d\n", execute(\&random_add));
    printf("random sub returned %d\n", execute(\&random_sub));
    ----------

    The operations I'm actually dealing with involve communication with an
    external program (database server) which might be running on a different
    computer located anywhere else in the world. There's an error recovery
    algorithm jointly implemtented by 'operation' (which signals the error)
    and 'execute' (which retries the failed application operation in case an
    error was signalled) which has to be wrapped around a number of
    different 'application operations', here represented as 'random_add' and
    'random_sub'. The main application logic decides which subroutine to
    call but the actual call itself is performed by an intermediate
    subroutine.
     
    Rainer Weikusat, Jan 9, 2014
    #7
  8. Jürgen Exner

    Dr.Ruud Guest

    On 2014-01-09 16:32, Rainer Weikusat wrote:

    > eval {
    > $rc = $sub->();
    > };
    >
    > $@ and do {
    > print STDERR ("\t** $@");
    > redo;
    > };


    Alternative:

    eval {
    $rc = $sub->();
    1; #success
    }
    or do {
    my $eval_error = $@ || 'Zombie Error';
    warn "\t** ", $eval_error, "\n";
    redo;
    };

    --
    Ruud
     
    Dr.Ruud, Jan 9, 2014
    #8
  9. "Dr.Ruud" <> writes:
    > On 2014-01-09 16:32, Rainer Weikusat wrote:
    >
    >> eval {
    >> $rc = $sub->();
    >> };
    >>
    >> $@ and do {
    >> print STDERR ("\t** $@");
    >> redo;
    >> };

    >
    > Alternative:
    >
    > eval {
    > $rc = $sub->();
    > 1; #success
    > }
    > or do {
    > my $eval_error = $@ || 'Zombie Error';
    > warn "\t** ", $eval_error, "\n";
    > redo;
    > };


    Better alternative:

    ($rc, $err) = $sub->();
    if ($err) {
    print STDERR ("A catastrophe occurred!\n");
     
    Rainer Weikusat, Jan 9, 2014
    #9
  10. >>>>> "RW" == Rainer Weikusat <> writes:

    RW> There are

    people who understand what "Do shut up" means and (self-evidently)
    people who do not.

    We are all well-aware of your hobbyhorse. Kindly stop riding it in
    public.

    Charlton






    --
    Charlton Wilbur
     
    Charlton Wilbur, Jan 13, 2014
    #10
    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:
    450
    Gunnar Hjalmarsson
    Dec 4, 2003
  2. Ketema

    References Subroutines and Arrays

    Ketema, Mar 5, 2004, in forum: Perl Misc
    Replies:
    2
    Views:
    141
  3. Rainer Weikusat
    Replies:
    1
    Views:
    136
    Rainer Weikusat
    Jan 4, 2014
  4. Peter J. Holzer
    Replies:
    1
    Views:
    85
    Rainer Weikusat
    Jan 7, 2014
  5. George Mpouras
    Replies:
    0
    Views:
    74
    George Mpouras
    Jan 5, 2014
Loading...

Share This Page