niXforums Forum Index
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   PreferencesPreferences   Log in to check your private messagesLog in to check your private messages   Log inLog in 
·  nixdoc.net ·  man pages ·  Linux HOWTOs ·  FreeBSD Tips ·  Forums
navigation Forum index » Programming » Perl
How to select subroutine
Post new topic   Reply to topic Page 1 of 1 [11 Posts] View previous topic :: View next topic
Author Message
James
*nix forums Guru


Joined: 09 Jun 2003
Posts: 306

PostPosted: Wed Jun 21, 2006 7:13 pm    Post subject: Re: How to select subroutine Reply with quote

On Wed, 21 Jun 2006 16:20:45 +0000, Glenn Jackman wrote:

Quote:
At 2006-06-20 08:17PM, James <hoosier45678@hotmail.com> wrote:
my $output = handler{$function}->(@ARGUMENTS);
missing $ -----------^

Good eye. I didn't actually test it.
Back to top
Glenn Jackman
*nix forums addict


Joined: 19 Apr 2005
Posts: 97

PostPosted: Wed Jun 21, 2006 4:20 pm    Post subject: Re: How to select subroutine Reply with quote

At 2006-06-20 08:17PM, James <hoosier45678@hotmail.com> wrote:
Quote:
my $output = handler{$function}->(@ARGUMENTS);
missing $ -----------^


--
Glenn Jackman
Ulterior Designer
Back to top
Ben Morrow
*nix forums Guru Wannabe


Joined: 24 Apr 2006
Posts: 193

PostPosted: Wed Jun 21, 2006 3:54 am    Post subject: Re: How to select subroutine Reply with quote

Quoth "Jan Fure" <janfure@gmail.com>:
Quote:

Ben Morrow wrote:
Yes, but it would be a bad idea. A better answer would be to use a
proper lookup table (in Perl, a hash).


I would do this like (untested):

my %dispatch = (
sr2 => sub { $_[1] ** 2 },
sr3 => sub { $_[1] ** 3 },
);

If I understand you right, you are proposing a hash, with keys from my
data, and anonymous subroutines linked to the keys.

Yes.

Quote:
For my actual code, this would be quite ugly, as the subroutines are
20+ lines of code.

FWIW, I don't see how

sub foo {
# 20 lines
}

sub bar {
# 20 lines
}

is substantially less ugly than

my %dispatch = (

foo => sub {
# 20 lines
},

bar => sub {
# 20 lines
},

);

; especially as the subs are all then kept together in an indented
block. However, if you disagree, then you can use

sub foo { ... }

sub bar { ... }

my %dispatch = (
foo => \&foo,
bar => \&bar,
);

just as easily.

Quote:
I also need the program to exit with appropriate error message, if
there is no match between existing subroutine and requested subroutine,

perldoc -f exists

Quote:
Could you elaborate on why it is a bad idea to let the subroutine name
be contained in the data?

Think about what happens if you get a key in your data that is the name
of some other sub, not part of your dispatch table.

If your next thought is to create a special package to keep these subs
in, then consider that a package is just a magical hash, and when you
don't need the magic (like now) it's safer, cleaner and faster to just
use a regular hash.

Ben

--
All persons, living or dead, are entirely coincidental.
benmorrow@tiscali.co.uk Kurt Vonnegut
Back to top
Tad McClellan
*nix forums Guru


Joined: 09 Mar 2005
Posts: 1647

PostPosted: Wed Jun 21, 2006 12:54 am    Post subject: Re: How to select subroutine Reply with quote

Jan Fure <janfure@gmail.com> wrote:


Quote:
I also need the program to exit with appropriate error message, if
there is no match between existing subroutine and requested subroutine,


die "appropriate error message" unless exists $dispatch{$ARGUMENTS[0]};


--
Tad McClellan SGML consulting
tadmc@augustmail.com Perl programming
Fort Worth, Texas
Back to top
Tad McClellan
*nix forums Guru


Joined: 09 Mar 2005
Posts: 1647

PostPosted: Wed Jun 21, 2006 12:51 am    Post subject: Re: How to select subroutine Reply with quote

Jan Fure <janfure@gmail.com> wrote:

Quote:
Could you elaborate on why it is a bad idea to let the subroutine name
^^^^
be contained in the data?


(because if a bad guy sprinkles the names of "bad" functions in
your data, you will happily execute it for him.
)

Your Question is Asked Frequently:

perldoc -q name

How can I use a variable as a variable name?


See also:

http://www.plover.com/~mjd/perl/varvarname.html
http://www.plover.com/~mjd/perl/varvarname2.html
http://www.plover.com/~mjd/perl/varvarname3.html

and:

http://perl.plover.com/FAQs/Namespaces.html

--
Tad McClellan SGML consulting
tadmc@augustmail.com Perl programming
Fort Worth, Texas
Back to top
simon.chao@gmail.com
*nix forums addict


Joined: 06 Oct 2005
Posts: 98

PostPosted: Wed Jun 21, 2006 12:36 am    Post subject: Re: How to select subroutine Reply with quote

Jan Fure wrote:
Quote:
Ben Morrow wrote:
Yes, but it would be a bad idea. A better answer would be to use a
proper lookup table (in Perl, a hash).


I would do this like (untested):

my %dispatch = (
sr2 => sub { $_[1] ** 2 },
sr3 => sub { $_[1] ** 3 },
);

Ben

Thanks for replying!

If I understand you right, you are proposing a hash, with keys from my
data, and anonymous subroutines linked to the keys.

For my actual code, this would be quite ugly, as the subroutines are
20+ lines of code.

This was just the shortest code I could come up with, that illustrated
the constraints:
1. Sub routine aquired from data.
2. Ability to pass output to the original function/subroutne call.
I also need the program to exit with appropriate error message, if
there is no match between existing subroutine and requested subroutine,
but I omitted that from the example code to keep it from getting too
long.

this is called a dispatch table.
Back to top
Tad McClellan
*nix forums Guru


Joined: 09 Mar 2005
Posts: 1647

PostPosted: Wed Jun 21, 2006 12:35 am    Post subject: Re: How to select subroutine Reply with quote

Jan Fure <janfure@gmail.com> wrote:

Quote:
I need to be able to select which subroutine to process a string with
based on the contents of the string.


That is known in computer science as a "dispatch table".


Quote:
I have written a code example of this, that uses a lookup table.

Is there a sensible way to do this without the lookup table,


No.

(but you can make a much nicer lookup table using a hash and coderefs.)


Quote:
i.e., can
I let the parsed string value be the subroutine name?


Yes you can, but you don't want to.

That would be using Symbolic References, which should be avoided
when possible...


Quote:
#!/usr/local/bin/perl -w
use strict;


.... and use strict disallows using symrefs anyway.


Quote:
my @DATA = <DATA>;
foreach (@DATA) {


Why read all of the lines when you are only going to process one
line at a time anyway?

while ( <DATA> ) {


Quote:
chomp;
my @ARGUMENTS = split / /;
my $output = subselect(@ARGUMENTS);


my %subs = ( sr2 => \&sr2, sr3 => \&sr3 ); # dispatch table
my $output = $subs{$ARGUMENTS[0]}->(@ARGUMENTS); # call the coderef


Quote:
sub subselect {
if ($_[0] eq 'sr2') {
my $return_value = sr2(@_);


And here we have the rare case where using an ampersand on a function
call _is_ what you want:

my $return_value = &sr2;

(but passing @_ explicitly is "better" IMO.)


Quote:
return $return_value;
}
if ($_[0] eq 'sr3') {
my $return_value = sr3(@_);
return $return_value;
}
}


--
Tad McClellan SGML consulting
tadmc@augustmail.com Perl programming
Fort Worth, Texas
Back to top
James
*nix forums Guru


Joined: 09 Jun 2003
Posts: 306

PostPosted: Wed Jun 21, 2006 12:17 am    Post subject: Re: How to select subroutine Reply with quote

On Tue, 20 Jun 2006 17:03:32 -0700, Jan Fure wrote:
Quote:
If I understand you right, you are proposing a hash, with keys from my
data, and anonymous subroutines linked to the keys.

For my actual code, this would be quite ugly, as the subroutines are
20+
lines of code.


they don't have to be anonymous, per se.

%handlers = (
sr2 => \&sr2,
sr3 => \&sr3,
);

while(<DATA>)
{
chomp;
my ($function, @ARGUMENTS) = split / /;
die "No handler for $function" unless defined $handler{$function};
my $output = handler{$function}->(@ARGUMENTS);
print "The chained output of 2 subroutines is $output\n";
}

sub sr2
{
$_[0] ** 2;
}

Quote:
This was just the shortest code I could come up with, that illustrated
the constraints:
1. Sub routine aquired from data.
2. Ability to pass output to the original function/subroutne call. I
also need the program to exit with appropriate error message, if there
is no match between existing subroutine and requested subroutine, but I
omitted that from the example code to keep it from getting too long.

Could you elaborate on why it is a bad idea to let the subroutine name
be contained in the data?

depends on the source of the data, but perldoc -f eval
Back to top
Jan Fure
*nix forums beginner


Joined: 20 Jun 2006
Posts: 2

PostPosted: Wed Jun 21, 2006 12:03 am    Post subject: Re: How to select subroutine Reply with quote

Ben Morrow wrote:
Quote:
Yes, but it would be a bad idea. A better answer would be to use a
proper lookup table (in Perl, a hash).


I would do this like (untested):

my %dispatch = (
sr2 => sub { $_[1] ** 2 },
sr3 => sub { $_[1] ** 3 },
);

Ben

Thanks for replying!


If I understand you right, you are proposing a hash, with keys from my
data, and anonymous subroutines linked to the keys.

For my actual code, this would be quite ugly, as the subroutines are
20+ lines of code.

This was just the shortest code I could come up with, that illustrated
the constraints:
1. Sub routine aquired from data.
2. Ability to pass output to the original function/subroutne call.
I also need the program to exit with appropriate error message, if
there is no match between existing subroutine and requested subroutine,
but I omitted that from the example code to keep it from getting too
long.

Could you elaborate on why it is a bad idea to let the subroutine name
be contained in the data?

Is there a way to improve the structure of the code I wrote, while
keeping the subroutines around? In my production code, I expect there
might be 15+ different sub routines.

Jan
Back to top
Ben Morrow
*nix forums Guru Wannabe


Joined: 24 Apr 2006
Posts: 193

PostPosted: Tue Jun 20, 2006 11:22 pm    Post subject: Re: How to select subroutine Reply with quote

Quoth "Jan Fure" <janfure@gmail.com>:
Quote:

I need to be able to select which subroutine to process a string with
based on the contents of the string.

I have written a code example of this, that uses a lookup table.

Is there a sensible way to do this without the lookup table, i.e., can
I let the parsed string value be the subroutine name?

Yes, but it would be a bad idea. A better answer would be to use a
proper lookup table (in Perl, a hash).

Quote:

#!/usr/local/bin/perl -w

use warnings;

is the modern version on -w.

Quote:
use strict;

my @DATA = <DATA>;
foreach (@DATA) {

If you want the data line-by-line, then read it line-by line.

Quote:
chomp;
my @ARGUMENTS = split / /;
my $output = subselect(@ARGUMENTS);
print "The chained output of 2 subroutines is $output\n";
}

sub subselect {
if ($_[0] eq 'sr2') {
my $return_value = sr2(@_);
return $return_value;
}
if ($_[0] eq 'sr3') {
my $return_value = sr3(@_);
return $return_value;
}
}

sub sr2 {
my $x2 = $_[1] ** 2;
return $x2;
}

sub sr3 {
my $x3 = $_[1] ** 3;
return $x3;
}

__DATA__
sr2 3.456
sr3 2
sr2 45

I would do this like (untested):

my %dispatch = (
sr2 => sub { $_[1] ** 2 },
sr3 => sub { $_[1] ** 3 },
);

local $\ = "\n"; # saves printing them all the time
while (<DATA>) {
my @args = split; # this doesn't quite do what you did before,
# but it's likely more flexible and more use.
# And you don't need the chomp.

my $output = $dispatch{$args[0]}->(@args);
print "the output of a sub in a dispatch table is $output";
}

__DATA__
sr2 3.456
sr3 2
sr2 45

I presume 'sr2' and 'sr3' are just examples? If not, I'd extract the '2'
and use it as a parameter rather than writing two separate subs.

Ben

--
The Earth is degenerating these days. Bribery and corruption abound.
Children no longer mind their parents, every man wants to write a book,
and it is evident that the end of the world is fast approaching.
Assyrian stone tablet, c.2800 BC benmorrow@tiscali.co.uk
Back to top
Jan Fure
*nix forums beginner


Joined: 20 Jun 2006
Posts: 2

PostPosted: Tue Jun 20, 2006 10:32 pm    Post subject: How to select subroutine Reply with quote

Hi;

I need to be able to select which subroutine to process a string with
based on the contents of the string.

I have written a code example of this, that uses a lookup table.

Is there a sensible way to do this without the lookup table, i.e., can
I let the parsed string value be the subroutine name?

Jan

#!/usr/local/bin/perl -w
use strict;

my @DATA = <DATA>;
foreach (@DATA) {
chomp;
my @ARGUMENTS = split / /;
my $output = subselect(@ARGUMENTS);
print "The chained output of 2 subroutines is $output\n";
}

sub subselect {
if ($_[0] eq 'sr2') {
my $return_value = sr2(@_);
return $return_value;
}
if ($_[0] eq 'sr3') {
my $return_value = sr3(@_);
return $return_value;
}
}

sub sr2 {
my $x2 = $_[1] ** 2;
return $x2;
}

sub sr3 {
my $x3 = $_[1] ** 3;
return $x3;
}

__DATA__
sr2 3.456
sr3 2
sr2 45
Back to top
Google

Back to top
Display posts from previous:   
Post new topic   Reply to topic Page 1 of 1 [11 Posts] View previous topic :: View next topic
The time now is Fri Nov 21, 2008 6:28 am | All times are GMT
navigation Forum index » Programming » Perl
Jump to:  

Similar Topics
Topic Author Forum Replies Last Post
No new posts Select statement Shamna Sybase 0 Mon Sep 17, 2007 6:03 am
No new posts ECPG (usage of simple select statement) Jasbinder Bali PostgreSQL 0 Fri Jul 21, 2006 3:28 am
No new posts Can't Select External Table from CSV File Resant Server 1 Fri Jul 21, 2006 2:45 am
No new posts subroutine weberw@adelphia.net Perl 6 Thu Jul 20, 2006 9:36 pm
No new posts Invalid syntax with STD() function when more than one fie... William Bronsema MySQL 1 Thu Jul 20, 2006 2:18 pm

Xbox Mod Chip | Loans | Free Online RPG | Mortgage Calculator | Books
Copyright © 2004-2005 DeniX Solutions SRL
 
Other DeniX Solutions sites: Unix/Linux blog |  electronics forum |  medicine forum |  science forum | 
Privacy Policy


Powered by phpBB © 2001, 2005 phpBB Group
[ Time: 0.3259s ][ Queries: 20 (0.2008s) ][ GZIP on - Debug on ]