From mark at purdue.edu Wed May 1 12:26:37 2019 From: mark at purdue.edu (Mark Senn) Date: Wed, 01 May 2019 15:26:37 -0400 Subject: [Purdue-pm] Purdue Perl Mongers challenge problem Message-ID: <3102.1556738797@pier.ecn.purdue.edu> See https://perlweeklychallenge.org/blog/perl-weekly-challenge-006/ for Challenge #1 of this week's Perl Weekly Challenge: Create a script which takes a list of numbers from command line and print the same in the compact form. For example, if you pass ?1,2,3,4,9,10,14,15,16? then it should print the compact form like ?1-4,9,10,14-16?. That's interesting but not enough of a challenge. For the Purdue Perl Mongers I add an additional criteria: You are only allowed to use while loops and s (substitution) commands to do the transformation. In my opinion, this leads to a solution that is more clear than anything else I've thought of. In software engineering, I've found that if a problem is in the string of characters domain in is usually easier to keep it in that domain if possible---instead of transforming to another domain (that requires more code), do some computations, and transforming back (even more code). (An exception is transforming from the time domain to the frequency domain and back for some kinds of problems.) I'll send out a link to a blog entry with my solution later. Hint: use Perl6. -mark From mark at purdue.edu Sat May 25 21:21:15 2019 From: mark at purdue.edu (Mark Senn) Date: Sun, 26 May 2019 00:21:15 -0400 Subject: [Purdue-pm] Perl 5 Dispatch Tables Message-ID: <39011.1558844475@pier.ecn.purdue.edu> I blogged about Perl 5 Dispatch Tables at https://engineering.purdue.edu/~mark/blog/perl-5-dispatch-tables.pdf In short, I don't use conventional dispatch tables because they violate the don't repeat yourself principle. I'm only dispatching to subs based on trusted information and the core of the idea is sub __SUB__add { return $_[0] + $_[1]; } my $_ = 'add 1 2'; # Split the line of text into words. my @word = split /\s+/, $_; # Get the command name from @word and leave the arguments # in @word. Prepend ?__SUB__? (two underlines before and # after ?SUB?) to the comand name. my $sub = ?__SUB__? . shift @word; # Is the "__SUB__$sub" name defined? defined(&$sub) or die qq/sub "$sub" is not defined/; # Do the command. say $sub->(@word); See the web page for more information. -mark From mark at purdue.edu Mon May 27 12:45:44 2019 From: mark at purdue.edu (Mark Senn) Date: Mon, 27 May 2019 15:45:44 -0400 Subject: [Purdue-pm] Damian Conway's "Why I love Perl 6" Message-ID: <6805.1558986344@pier.ecn.purdue.edu> See http://blogs.perl.org/users/damian_conway/2019/05/why-i-love-perl-6.html for Damian's short very article about Perl 6. He is by far my favorite Perl speaker. You may find his talk at https://www.youtube.com/watch?v=ob6YHpcXmTg (skip to 8:25 for the meat of the talk) interesting. It describes how to [inpractically ---mark] implement some Perl 6 ideas in Perl 5. If you don't what my $n = 2; print "$n"; $n = $n + 1; does in Perl 5 and don't know what object oriented programming is you won't be able to actively understand the talk. I've stolen things in his presentation style to use in my talks. -mark From gizmo at purdue.edu Tue May 28 11:17:17 2019 From: gizmo at purdue.edu (Joe Kline) Date: Tue, 28 May 2019 14:17:17 -0400 Subject: [Purdue-pm] Perl 5 Dispatch Tables In-Reply-To: <39011.1558844475@pier.ecn.purdue.edu> References: <39011.1558844475@pier.ecn.purdue.edu> Message-ID: <7198ef08-11f0-05fb-9ea6-164e81de5d04@purdue.edu> Mark, I'm not sure how a typical dispatch table is violating DRY. What I typically do is something like: my ($dispatch_table) = create_dispatch_table($config_info_if_needed); sub create_dispatch_table ($config) { my $dispatch = { 'thing_one' => \&thing_one, 'thing_two' => \&thing_two, }; return($dispatch); } I typically don't have some subs I'm calling but directly calling an anonymous sub go in there without creating a defined sub. I have been using the table something like: $key = q(some token or task based on a keyword); if ( exists $dispatch->{$key} ) { ($some_ref) = $dispatch->{$key}->($key, $some_arg, $another_arg, $baz); } As near as I can detail I'm not using the same code over again in a copy and paste fashion. The only repeating is the variable name the table is hanging out in and maybe the key used to call the associated sub ref. joe -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 198 bytes Desc: OpenPGP digital signature URL: From jacoby.david at gmail.com Tue May 28 16:34:39 2019 From: jacoby.david at gmail.com (Dave Jacoby) Date: Tue, 28 May 2019 19:34:39 -0400 Subject: [Purdue-pm] Perl 5 Dispatch Tables In-Reply-To: <7198ef08-11f0-05fb-9ea6-164e81de5d04@purdue.edu> References: <39011.1558844475@pier.ecn.purdue.edu> <7198ef08-11f0-05fb-9ea6-164e81de5d04@purdue.edu> Message-ID: I also don't see how dispatch tables violate DRY. I think the better way to consider them as a special case statement (without fallthrough). Consider perlbrew. Some of the commands are init, install, switch and use. if ( $ARGV[0] eq 'init' ) { initialize() } else if ( $ARGV[0] eq 'install' ) { install(@ARGV) } ... else { say 'Not a valid command' } or use Switch; switch( $ARGV[0] ){ case 'init' { initialize() } case 'install' { install( @ARGV ) } ... else { say "Not a valid command" } } becomes my %dispatch { 'init' => &initialize , 'install' => &install, } if ( defined $dispatch{ $ARGV[0] } ) { &$dispatch(@ARGV) ; } else { say "Not a valid command" } With some playing around, you can check $ARGV[0] against keys %dispatch, finding the Levenshtein distance, to respond to a typo like "imit" with 'did you mean "init"?' This last way *IS* pretty much how perlbrew works. On Tue, May 28, 2019 at 3:25 PM Joe Kline wrote: > Mark, > > I'm not sure how a typical dispatch table is violating DRY. > > What I typically do is something like: > > my ($dispatch_table) = create_dispatch_table($config_info_if_needed); > > sub create_dispatch_table ($config) { > my $dispatch = { > 'thing_one' => \&thing_one, > 'thing_two' => \&thing_two, > }; > return($dispatch); > } > > I typically don't have some subs I'm calling but directly calling an > anonymous sub go in there without creating a defined sub. > > I have been using the table something like: > > $key = q(some token or task based on a keyword); > > if ( exists $dispatch->{$key} ) { > ($some_ref) = $dispatch->{$key}->($key, $some_arg, $another_arg, $baz); > } > > > As near as I can detail I'm not using the same code over again in a copy > and paste fashion. > > The only repeating is the variable name the table is hanging out in and > maybe the key used to call the associated sub ref. > > joe > > _______________________________________________ > Purdue-pm mailing list > Purdue-pm at pm.org > https://mail.pm.org/mailman/listinfo/purdue-pm > -- Dave Jacoby jacoby.david at gmail.com Don't panic when the crisis is happening, or you won't enjoy it. -------------- next part -------------- An HTML attachment was scrubbed... URL: From mark at purdue.edu Tue May 28 17:20:45 2019 From: mark at purdue.edu (Mark Senn) Date: Tue, 28 May 2019 20:20:45 -0400 Subject: [Purdue-pm] Perl 5 Dispatch Tables In-Reply-To: <7198ef08-11f0-05fb-9ea6-164e81de5d04@purdue.edu> References: <39011.1558844475@pier.ecn.purdue.edu> <7198ef08-11f0-05fb-9ea6-164e81de5d04@purdue.edu> Message-ID: <36587.1559089245@pier.ecn.purdue.edu> > I'm not sure how a typical dispatch table is violating DRY. > [... -mark] > sub create_dispatch_table ($config) { > my $dispatch = { > 'thing_one' => \&thing_one, > 'thing_two' => \&thing_two, > }; > return($dispatch); > } > [... -mark] From https://dzone.com/articles/software-design-principles-dry-and-kiss The DRY Principle: Don't Repeat Yourself DRY stand for "Don't Repeat Yourself," a basic principle of software development aimed at reducing repetition of information. >From my earlier message: In short, I don't use conventional dispatch tables because they violate the don't repeat yourself principle. I'm only dispatching to subs based on trusted information and the core of the idea is I should have written I only use dispatch tables to dispatch to non-anonymous subs based on trusted information. To me, my $dispatch = { 'thing_one' => \&thing_one, 'thing_two' => \&thing_two, }; is an example of repetition. For the case I wrote about, this code is not needed. Since it's not needed I don't use it---it's just more code to support. Given a word w, I always call a subroutine whose name can be computed from w. In other words, I don't need to do 'thing_one' -> \&some_name_that_cannot_be_be computed_from_thing_one -mark From jacoby.david at gmail.com Wed May 29 07:50:23 2019 From: jacoby.david at gmail.com (Dave Jacoby) Date: Wed, 29 May 2019 10:50:23 -0400 Subject: [Purdue-pm] Perl 5 Dispatch Tables In-Reply-To: <36587.1559089245@pier.ecn.purdue.edu> References: <39011.1558844475@pier.ecn.purdue.edu> <7198ef08-11f0-05fb-9ea6-164e81de5d04@purdue.edu> <36587.1559089245@pier.ecn.purdue.edu> Message-ID: I get that. This reminds me of the mess I went through to auto-populate things based on the symbol table. You have a main program that's basically this: use strict ; use warnings ; my $api = API->new(@ARGV) ; $api->run() ; package API ; use lib '/depot/gcore/apps/lib' ; use base 'API_Base' ; use API_PED ; ----- And then API_Base cut down looks like sub new ( $class, @argv ) { my $self ; my $cgi = CGI->new() ; $self->{method} = $ENV{REQUEST_METHOD} || 'GET' ; %{ $self->{param} } = map { $_ => scalar $cgi->param($_) } $cgi->param() ; ( undef, @{ $self->{pathinfo} } ) = split m{/}mxs, $cgi->path_info() ; return bless $self, $class ; } # I honestly don't know why I can't combine this with run_command, but # I tried it and gave up sub run ($self) { my @vars = map{ $self->{$_} } qw{ pathinfo param method } ; return $self->run_command( $self->{pathinfo}, $self->{param}, $self->{method} ) ; } # where the work is handled sub run_command ( $self, $pathinfo, $param, $method ) { my $command = $pathinfo->[0] || 'test' ; my $s = $self->can("api_$command") ; # can() tells us if an object has a method called METHOD, which is # good for telling if it is a usable function # http://perldoc.perl.org/UNIVERSAL.html # y/-/_/ because function names cannot be foo-bar, only foo_bar if (!$s) { $command =~ y/-/_/ ; $s = $self->can("api_$command") ; } # after this, we'll fail out if it still isn't in the table if (!$s) { $self->wrap( $self->fail( $pathinfo, $param, $method ) ) ; exit ; } #if it isn't a code ref, we'll fail out as well if ( 'CODE' ne ref $s ) { $self->wrap( $self->fail( $pathinfo, $param, $method ) ) ; exit ; } # $self->$s if callable, so we'll call it. return $self->wrap( $self->$s( $pathinfo, $param, $method ) ) ; } ---- Where the key is, given looking for an entry in the Purdue Electronic Directory, the call would be in the symbol table as api_ped, so we see if that function exists, using can('api_ped'). So, we need to be sure that sub api_ped() is in there. package API_PED ; # simlified somewhat our $VERSION = 0.1 ; our @EXPORT ; # because sub NAME and push @EXPORT, NAME violates DRY for my $entry ( keys %API_PED:: ) { next if $entry !~ /^api_/mxs ; push @EXPORT, $entry ; } sub api_ped ( $self , $etc ) { # talks to PED returns response } ---- (Lots of web API JSON specific things cut) So the behavior of program.pl here is determined almost entirely by which modules it uses and if the sub names are prepended with 'api_'. Yes, that CAN violate DRY, but 1) the benefits of data-driven dev are there and powerful, and 2) it doesn't necessary violate DRY. So, I guess the question moves to what is worse: DRY or Scary Magic. On Tue, May 28, 2019 at 8:20 PM Mark Senn wrote: > > I'm not sure how a typical dispatch table is violating DRY. > > [... -mark] > > sub create_dispatch_table ($config) { > > my $dispatch = { > > 'thing_one' => \&thing_one, > > 'thing_two' => \&thing_two, > > }; > > return($dispatch); > > } > > [... -mark] > > From > https://dzone.com/articles/software-design-principles-dry-and-kiss > The DRY Principle: Don't Repeat Yourself > DRY stand for "Don't Repeat Yourself," a basic principle of software > development aimed at reducing repetition of information. > > From my earlier message: > In short, I don't use conventional dispatch tables because they > violate the don't repeat yourself principle. I'm only dispatching > to subs based on trusted information and the core of the idea is > > I should have written > I only use dispatch tables to dispatch to non-anonymous subs > based on trusted information. > > To me, > my $dispatch = { > 'thing_one' => \&thing_one, > 'thing_two' => \&thing_two, > }; > is an example of repetition. For the case I wrote about, this code > is not needed. Since it's not needed I don't use it---it's just > more code to support. Given a word w, I always call a subroutine > whose name can be computed from w. In other words, I don't need to do > 'thing_one' -> \&some_name_that_cannot_be_be computed_from_thing_one > > -mark > _______________________________________________ > Purdue-pm mailing list > Purdue-pm at pm.org > https://mail.pm.org/mailman/listinfo/purdue-pm > -- Dave Jacoby jacoby.david at gmail.com Don't panic when the crisis is happening, or you won't enjoy it. -------------- next part -------------- An HTML attachment was scrubbed... URL: From jacoby.david at gmail.com Wed May 29 08:57:59 2019 From: jacoby.david at gmail.com (Dave Jacoby) Date: Wed, 29 May 2019 11:57:59 -0400 Subject: [Purdue-pm] Perl 5 Dispatch Tables In-Reply-To: References: <39011.1558844475@pier.ecn.purdue.edu> <7198ef08-11f0-05fb-9ea6-164e81de5d04@purdue.edu> <36587.1559089245@pier.ecn.purdue.edu> Message-ID: Of course, the OTHER option is ... bulky? my %dispatch; $dispatch{ foo } = sub { ... code goes here .. } $dispatch{ bar } = sub { ... code goes here .. } $dispatch{ blee } = sub { ... code goes here .. } code reuse is almost impossible by this method. On Wed, May 29, 2019 at 10:50 AM Dave Jacoby wrote: > I get that. This reminds me of the mess I went through to auto-populate > things based on the symbol table. > > You have a main program that's basically this: > > use strict ; > use warnings ; > > my $api = API->new(@ARGV) ; > $api->run() ; > > package API ; > use lib '/depot/gcore/apps/lib' ; > use base 'API_Base' ; > use API_PED ; > > ----- And then API_Base cut down looks like > sub new ( $class, @argv ) { > my $self ; > my $cgi = CGI->new() ; > $self->{method} = $ENV{REQUEST_METHOD} || 'GET' ; > %{ $self->{param} } = map { $_ => scalar $cgi->param($_) } $cgi->param() ; > ( undef, @{ $self->{pathinfo} } ) = split m{/}mxs, $cgi->path_info() ; > return bless $self, $class ; > } > > # I honestly don't know why I can't combine this with run_command, but > # I tried it and gave up > sub run ($self) { > my @vars = map{ $self->{$_} } qw{ pathinfo param method } ; > return $self->run_command( $self->{pathinfo}, $self->{param}, $self->{method} > ) ; > } > > # where the work is handled > sub run_command ( $self, $pathinfo, $param, $method ) { > my $command = $pathinfo->[0] || 'test' ; > my $s = $self->can("api_$command") ; > > # can() tells us if an object has a method called METHOD, which is > # good for telling if it is a usable function > # http://perldoc.perl.org/UNIVERSAL.html > > # y/-/_/ because function names cannot be foo-bar, only foo_bar > if (!$s) { > $command =~ y/-/_/ ; > $s = $self->can("api_$command") ; > } > > # after this, we'll fail out if it still isn't in the table > if (!$s) { > $self->wrap( $self->fail( $pathinfo, $param, $method ) ) ; > exit ; > } > > #if it isn't a code ref, we'll fail out as well > if ( 'CODE' ne ref $s ) { > $self->wrap( $self->fail( $pathinfo, $param, $method ) ) ; > exit ; > } > # $self->$s if callable, so we'll call it. > return $self->wrap( $self->$s( $pathinfo, $param, $method ) ) ; > } > > ---- > > Where the key is, given looking for an entry in the Purdue Electronic > Directory, the call would be in the symbol table as api_ped, so we see > if that function exists, using can('api_ped'). So, we need to be sure that > sub api_ped() is in there. > package API_PED ; > > # simlified somewhat > our $VERSION = 0.1 ; > our @EXPORT ; > # because sub NAME and push @EXPORT, NAME violates DRY > for my $entry ( keys %API_PED:: ) { > next if $entry !~ /^api_/mxs ; > push @EXPORT, $entry ; > } > > sub api_ped ( $self , $etc ) { > # talks to PED returns response > } > ---- > (Lots of web API JSON specific things cut) > > So the behavior of program.pl here is determined almost entirely by > which modules it uses and if the sub names are prepended with 'api_'. > > Yes, that CAN violate DRY, but 1) the benefits of data-driven dev > are there and powerful, and 2) it doesn't necessary violate DRY. So, I > guess the question moves to what is worse: DRY or Scary Magic. > > On Tue, May 28, 2019 at 8:20 PM Mark Senn wrote: > >> > I'm not sure how a typical dispatch table is violating DRY. >> > [... -mark] >> > sub create_dispatch_table ($config) { >> > my $dispatch = { >> > 'thing_one' => \&thing_one, >> > 'thing_two' => \&thing_two, >> > }; >> > return($dispatch); >> > } >> > [... -mark] >> >> From >> https://dzone.com/articles/software-design-principles-dry-and-kiss >> The DRY Principle: Don't Repeat Yourself >> DRY stand for "Don't Repeat Yourself," a basic principle of software >> development aimed at reducing repetition of information. >> >> From my earlier message: >> In short, I don't use conventional dispatch tables because they >> violate the don't repeat yourself principle. I'm only dispatching >> to subs based on trusted information and the core of the idea is >> >> I should have written >> I only use dispatch tables to dispatch to non-anonymous subs >> based on trusted information. >> >> To me, >> my $dispatch = { >> 'thing_one' => \&thing_one, >> 'thing_two' => \&thing_two, >> }; >> is an example of repetition. For the case I wrote about, this code >> is not needed. Since it's not needed I don't use it---it's just >> more code to support. Given a word w, I always call a subroutine >> whose name can be computed from w. In other words, I don't need to do >> 'thing_one' -> \&some_name_that_cannot_be_be computed_from_thing_one >> >> -mark >> _______________________________________________ >> Purdue-pm mailing list >> Purdue-pm at pm.org >> https://mail.pm.org/mailman/listinfo/purdue-pm >> > > > -- > Dave Jacoby > jacoby.david at gmail.com > > Don't panic when the crisis is happening, or you won't enjoy it. > -- Dave Jacoby jacoby.david at gmail.com Don't panic when the crisis is happening, or you won't enjoy it. -------------- next part -------------- An HTML attachment was scrubbed... URL: From jacoby.david at gmail.com Thu May 30 09:30:16 2019 From: jacoby.david at gmail.com (Dave Jacoby) Date: Thu, 30 May 2019 12:30:16 -0400 Subject: [Purdue-pm] Perl 5 Dispatch Tables In-Reply-To: References: <39011.1558844475@pier.ecn.purdue.edu> <7198ef08-11f0-05fb-9ea6-164e81de5d04@purdue.edu> <36587.1559089245@pier.ecn.purdue.edu> Message-ID: Mark, I am starting to write something on this. Would you want me to link to your PDF? On Wed, May 29, 2019 at 11:57 AM Dave Jacoby wrote: > Of course, the OTHER option is ... bulky? > > my %dispatch; > $dispatch{ foo } = sub { ... code goes here .. } > $dispatch{ bar } = sub { ... code goes here .. } > $dispatch{ blee } = sub { ... code goes here .. } > > code reuse is almost impossible by this method. > > > On Wed, May 29, 2019 at 10:50 AM Dave Jacoby > wrote: > >> I get that. This reminds me of the mess I went through to auto-populate >> things based on the symbol table. >> >> You have a main program that's basically this: >> >> use strict ; >> use warnings ; >> >> my $api = API->new(@ARGV) ; >> $api->run() ; >> >> package API ; >> use lib '/depot/gcore/apps/lib' ; >> use base 'API_Base' ; >> use API_PED ; >> >> ----- And then API_Base cut down looks like >> sub new ( $class, @argv ) { >> my $self ; >> my $cgi = CGI->new() ; >> $self->{method} = $ENV{REQUEST_METHOD} || 'GET' ; >> %{ $self->{param} } = map { $_ => scalar $cgi->param($_) } $cgi->param() >> ; >> ( undef, @{ $self->{pathinfo} } ) = split m{/}mxs, $cgi->path_info() ; >> return bless $self, $class ; >> } >> >> # I honestly don't know why I can't combine this with run_command, but >> # I tried it and gave up >> sub run ($self) { >> my @vars = map{ $self->{$_} } qw{ pathinfo param method } ; >> return $self->run_command( $self->{pathinfo}, $self->{param}, $self->{method} >> ) ; >> } >> >> # where the work is handled >> sub run_command ( $self, $pathinfo, $param, $method ) { >> my $command = $pathinfo->[0] || 'test' ; >> my $s = $self->can("api_$command") ; >> >> # can() tells us if an object has a method called METHOD, which is >> # good for telling if it is a usable function >> # http://perldoc.perl.org/UNIVERSAL.html >> >> # y/-/_/ because function names cannot be foo-bar, only foo_bar >> if (!$s) { >> $command =~ y/-/_/ ; >> $s = $self->can("api_$command") ; >> } >> >> # after this, we'll fail out if it still isn't in the table >> if (!$s) { >> $self->wrap( $self->fail( $pathinfo, $param, $method ) ) ; >> exit ; >> } >> >> #if it isn't a code ref, we'll fail out as well >> if ( 'CODE' ne ref $s ) { >> $self->wrap( $self->fail( $pathinfo, $param, $method ) ) ; >> exit ; >> } >> # $self->$s if callable, so we'll call it. >> return $self->wrap( $self->$s( $pathinfo, $param, $method ) ) ; >> } >> >> ---- >> >> Where the key is, given looking for an entry in the Purdue Electronic >> Directory, the call would be in the symbol table as api_ped, so we see >> if that function exists, using can('api_ped'). So, we need to be sure >> that sub api_ped() is in there. >> package API_PED ; >> >> # simlified somewhat >> our $VERSION = 0.1 ; >> our @EXPORT ; >> # because sub NAME and push @EXPORT, NAME violates DRY >> for my $entry ( keys %API_PED:: ) { >> next if $entry !~ /^api_/mxs ; >> push @EXPORT, $entry ; >> } >> >> sub api_ped ( $self , $etc ) { >> # talks to PED returns response >> } >> ---- >> (Lots of web API JSON specific things cut) >> >> So the behavior of program.pl here is determined almost entirely by >> which modules it uses and if the sub names are prepended with 'api_'. >> >> Yes, that CAN violate DRY, but 1) the benefits of data-driven dev >> are there and powerful, and 2) it doesn't necessary violate DRY. So, I >> guess the question moves to what is worse: DRY or Scary Magic. >> >> On Tue, May 28, 2019 at 8:20 PM Mark Senn wrote: >> >>> > I'm not sure how a typical dispatch table is violating DRY. >>> > [... -mark] >>> > sub create_dispatch_table ($config) { >>> > my $dispatch = { >>> > 'thing_one' => \&thing_one, >>> > 'thing_two' => \&thing_two, >>> > }; >>> > return($dispatch); >>> > } >>> > [... -mark] >>> >>> From >>> https://dzone.com/articles/software-design-principles-dry-and-kiss >>> The DRY Principle: Don't Repeat Yourself >>> DRY stand for "Don't Repeat Yourself," a basic principle of software >>> development aimed at reducing repetition of information. >>> >>> From my earlier message: >>> In short, I don't use conventional dispatch tables because they >>> violate the don't repeat yourself principle. I'm only dispatching >>> to subs based on trusted information and the core of the idea is >>> >>> I should have written >>> I only use dispatch tables to dispatch to non-anonymous subs >>> based on trusted information. >>> >>> To me, >>> my $dispatch = { >>> 'thing_one' => \&thing_one, >>> 'thing_two' => \&thing_two, >>> }; >>> is an example of repetition. For the case I wrote about, this code >>> is not needed. Since it's not needed I don't use it---it's just >>> more code to support. Given a word w, I always call a subroutine >>> whose name can be computed from w. In other words, I don't need to do >>> 'thing_one' -> \&some_name_that_cannot_be_be computed_from_thing_one >>> >>> -mark >>> _______________________________________________ >>> Purdue-pm mailing list >>> Purdue-pm at pm.org >>> https://mail.pm.org/mailman/listinfo/purdue-pm >>> >> >> >> -- >> Dave Jacoby >> jacoby.david at gmail.com >> >> Don't panic when the crisis is happening, or you won't enjoy it. >> > > > -- > Dave Jacoby > jacoby.david at gmail.com > > Don't panic when the crisis is happening, or you won't enjoy it. > -- Dave Jacoby jacoby.david at gmail.com Don't panic when the crisis is happening, or you won't enjoy it. -------------- next part -------------- An HTML attachment was scrubbed... URL: