Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > Re: Help with understanding references to subroutines

Reply
Thread Tools

Re: Help with understanding references to subroutines

 
 
Jürgen Exner
Guest
Posts: n/a
 
      01-05-2014
Dave Stratford <(E-Mail Removed)> 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
 
Reply With Quote
 
 
 
 
Rainer Weikusat
Guest
Posts: n/a
 
      01-08-2014
Dave Stratford <(E-Mail Removed)> writes:
> In article <(E-Mail Removed)>,
> Jürgen Exner <(E-Mail Removed)> wrote:
>> Dave Stratford <(E-Mail Removed)> 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.
 
Reply With Quote
 
 
 
 
Rainer Weikusat
Guest
Posts: n/a
 
      01-08-2014
Ben Morrow <(E-Mail Removed)> writes:
> Quoth Rainer Weikusat <(E-Mail Removed)>:
>>
>> 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.
 
Reply With Quote
 
Rainer Weikusat
Guest
Posts: n/a
 
      01-08-2014
Ben Morrow <(E-Mail Removed)> writes:
> Quoth Rainer Weikusat <(E-Mail Removed)>:
>> Ben Morrow <(E-Mail Removed)> writes:
>> > Quoth Rainer Weikusat <(E-Mail Removed)>:
>> >>
>> >> 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%27s_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.




 
Reply With Quote
 
Uri Guttman
Guest
Posts: n/a
 
      01-08-2014
>>>>> "DS" == Dave Stratford <(E-Mail Removed)> 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


 
Reply With Quote
 
Tim McDaniel
Guest
Posts: n/a
 
      01-09-2014
In article <(E-Mail Removed)>,
Dave Stratford <(E-Mail Removed)> 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, http://www.velocityreviews.com/forums/(E-Mail Removed)


 
Reply With Quote
 
Rainer Weikusat
Guest
Posts: n/a
 
      01-09-2014
Dave Stratford <(E-Mail Removed)> writes:
> In article <(E-Mail Removed)>,
> Rainer Weikusat <(E-Mail Removed)> wrote:
>> Dave Stratford <(E-Mail Removed)> writes:
>> > In article <(E-Mail Removed)>,
>> > Jürgen Exner <(E-Mail Removed)> wrote:
>> >> Dave Stratford <(E-Mail Removed)> 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("**** 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.
 
Reply With Quote
 
Dr.Ruud
Guest
Posts: n/a
 
      01-09-2014
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

 
Reply With Quote
 
Rainer Weikusat
Guest
Posts: n/a
 
      01-09-2014
"Dr.Ruud" <(E-Mail Removed)> 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");
 
Reply With Quote
 
Charlton Wilbur
Guest
Posts: n/a
 
      01-13-2014
>>>>> "RW" == Rainer Weikusat <(E-Mail Removed)> 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
(E-Mail Removed)
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: Help with understanding references to subroutines Peter J. Holzer Perl Misc 1 01-07-2014 01:45 PM
Re: Help with understanding references to subroutines Rainer Weikusat Perl Misc 1 01-04-2014 08:49 PM
Help with printing a bit pattern with printf and %x matt.jaffe@gmail.com C Programming 9 04-19-2013 12:14 PM
References Subroutines and Arrays Ketema Perl Misc 2 03-06-2004 01:49 PM
References and subroutines ReaprZero Perl 1 12-04-2003 02:53 PM



Advertisments