Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Call a Sub by Name 3

Status
Not open for further replies.

rvBasic

Programmer
Oct 22, 2000
414
0
0
BE
I have to validate a somewhat 300 data fields. In principle each field can have a different data validation routine. A nested if, 300 levels deep seems to me not the ideal solution. So I hit upon the idea of constructing a hash with matching FieldName (key) / SubName (data = Name of sub to call for validation).

But can I call a function this way?

_________________________________
In theory, there is no difference between theory and practice. In practice, there is. [attributed to Yogi Berra]
 
Using a dispatch table:
Code:
sub foo {
   print "foo\n";
}

sub bar {
   print "bar\n";
}

my %subs = (
   foo => \&foo,
   bar => \&bar,
   baz => sub { print "baz\n"; }
);

$subs{ foo }->();
 
Thanks, that's great! But ... the question was more subtle: I want to read the FieldName/Subname association from an external file and then call the Sub. I solved that by adding a second hash %fields. Any suggestions for further improvement?

sub foo {
print "foo\n";
}

sub bar {
print "bar\n";
}

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

my %fields = (
name => 'foo',
address => 'bar',
state => 'foo'
);

$subs{ $fields{name} }->();


In this example the fields name and state will call upon the same sub foo.


_________________________________
In theory, there is no difference between theory and practice. In practice, there is. [attributed to Yogi Berra]
 
As per my example above, you can simply do this as last line of your example:
Code:
&{$fields{name}}();
The [tt]%subs[/tt] hash is unnecessary (and a dangerous duplicate?), and of course you can read the contents of [tt]%fields[/tt] from whatever file you want.

prex1
: Online tools for structural design
: Magnetic brakes for fun rides
: Air bearing pads
 
Prex1: That's even greater! Our posts must have crossed over.

_________________________________
In theory, there is no difference between theory and practice. In practice, there is. [attributed to Yogi Berra]
 
rvBasic said:
Prex1: That's even greater!
I have to disagree. That's using what's known as "soft references", which regular visitors will tell you are a pet hate of mine :). This particular use of them is relatively safe, as you've effectively created a dispatch table anyway, so as to validate your input. However, it still won't work with strict checking turned on (you DO have strict checking turned on, don't you?). For more on why soft references are bad in general, have a read of this.

When adding to the example I posted, there's no need to define a second hash. If you want multiple names to map to the same subroutine, then you can do that easily, like so:
Code:
my %subs = (
    name => \&foo,
    address => \&bar,
    state => \&foo
    );

 
You don't even need any of this judging by your first post: "300 fields to validate". There is no getting around the validation so having a seperate function for each field is just extra code. But your free to choose whatever method yu think is best for your situation.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
Ishnid: ...I have to disagree...
I'm confused now: do you disagree with prex1's solution or with your own? I'm not sure I fully understand what you mean by soft references: does it include any use op the -> operator or just the ${} dereferencing?

I'm a vbasic programmer, but for whatever reason I have to use Perl for this particular application. Needless to say, it's a cultural shock. I just managed to read halfway through Perl in 24 hours, which is probably an oxymoron. So, I barely discovered references and certainly not the -> operator.

Which explains perhaps my confusion.

What I'm missing most is the simplicity of the SELECT Case statement, which allows for a simple structure like:

SELECT CASE FieldName
CASE "Name"
Call VerifyName
CASE "Address"
Call VerifyAdress
... and so on.

I can't believe that normally I have to replace all of this with nested ifs?

But .. I may even like Perl in the future,


_________________________________
In theory, there is no difference between theory and practice. In practice, there is. [attributed to Yogi Berra]
 
He disagrees with prex1's suggestion, as do I. Soft references are not good for a variety of reasons. Ishnids link seems to be dead or temporarily unavailable. Soft references allow for buggy code, you should just avoid them as much as possible.

What is the difference between 300 "if" conditions and 300 select/case statements? Like I said before, introducing a layer of function calls for each field to validate seems totally unnecessary to me.

If you want to learn about refernces, get "Advanced Perl Programming". You have one of the worst perl books for people that need to write serious code.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
...You have one of the worst perl books...

You have to start somewhere!

In principle there is no difference between 300 Cases and 300 ifs. In practice adding or deleteing a "Case" is much simpler (for me) than interfering with nested if/elseifs. I'm sure I will break the structure if I do the latter.

In practice there will be 300 fields, but some of them will be verified by the same routine (e.g. check if it is numeric and within certain bounds). So I expect much fewer routines than cases.

Intermediate Programming is already on its way (says Amazon). Advanced will follow eventually


_________________________________
In theory, there is no difference between theory and practice. In practice, there is. [attributed to Yogi Berra]
 
I realize you have to start somewhere and if you have nothing to compare it to you would never know how bad that book is, thus my comment. I have many books to compare it to so I do know how bad it is for serious work.

You may not even need any if/elsif blocks for validating your data/fields. Hard to say without knowing what you need to validate.


------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
Would you please make this a FAQ as this contains some very valuable information.
thanks.
 
Make what a FAQ? Can you be more specific please.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
Of course what ishnid and KevinADC state about soft references is correct, but in my personal opinion to put at every and each occasion
YOU SHALL [tt]use strict[/tt]
as the 11th commandment is excessive, especially for a starter.
My advice to rvBasic is to go on freely with your experimentation: if you ever will like perl, you'll have the time to understand the positive (and the negative?) of [tt]use strict[/tt].
Personally I love the freedom of perl (as compared for example to tcl/tk, that must have been written by a taleban) and would like to continue to be free to do what suits my needs.
Concerning the SELECT CASE, it is written in the documentation that perl has so many ways of doing it, that it was unnecessary to provide a specific construct. That's not true in my opinion, but...
I like this construct:
Code:
local($_);
for($fieldname){
  /^Name$/&&VerifyName();
  /^Address$/&&VerifyAddress();
  /^Other$/&&do{
    Do something here;
    last;
  };
  VerifyDefault();
}
The problem with it is that if you forget the [tt]last;[/tt] where it is needed...[3eyes]

prex1
: Online tools for structural design
: Magnetic brakes for fun rides
: Air bearing pads
 
You can write something similar to a CASE statement like this:

if($FieldName eq "Name"){
[tab]VerifyName
} elseif($FieldName eq "Address"){
[tab]VerifyAdress
}

It's got a similar structure to a dispatch table, and is easier to read and use.

Mike

When working on any project the value of other people is exactly that - they are other people. The mismatch between their views and the view you've been contentedly assuming is right, is where that value lies.
 
MikeLacey: ...It's got a similar structure to a dispatch table, and is easier to read and use. ...

But imagine that extended over several pages (screens). And ..you suppose that the field names will be known at the time the program is written.

Let me perhaps explain the application and my view of handling it: In fact I have several CSV files that are mainly extracted from worksheets. Each of them contains a "header" record with FieldNames and then the data records. Each file contains several but not all possible fields. Different files may contain the same field (e.g. an IP address).

The application will get a file, has to discover which type of file it is (by checking its directory) and check the validity of its fields.

The design I thought of was creating a different database table for each file type. It contains for that file the name of the fields to be checked (not all fields must be validated) and the name of the routine to check it. (as a twist for some fields I can put a regex in that database field)

In principle the program is now simple: First I write all possible checking routines and put them at the front of the program. The main program then consists of
1. building a hash %subs (Routine name => Reference)
2. looking at the database table for that file, extracting the field names to be checked and building a hash %Fields (Fieldname => Program Name)
3 and finally foreach field in %fields calling the corresponding routine (or regexp).

The advantage of this approach is that if in the future fields are shuffled around from one file to another, I only have to change the database table information - not the program. Also if for whatever reason the regexp changes its outside the program.

Does this makes sense?

If I understand the comments correctly then

1. Ishnid's approach requires me to build the %subs (which is static) but still allows the use strict;
2. Prex1's approach doesn't require the %subs to be build, which is more flexible but uses a "soft reference" in which case use strict can no longer be used.

Or should I stick to if/elsif in which case the program becomes much more entangled?

And many thanks to all who contributed so far.

_________________________________
In theory, there is no difference between theory and practice. In practice, there is. [attributed to Yogi Berra]
 
ishnid,
concerning your last comments, consider that, instead of a database file, your [tt]%subs[/tt] hash may be defined in a program file that will be [tt]require[/tt]'d by the main program. Also you could [tt]require[/tt] a different file with [tt]%subs[/tt] for each of your file types. In this way you can use both types of approach (and by the way, [tt]use strict[/tt] may also be temporarily suspended with [tt]no strict[/tt]). Consider however that, if more than one file type will be checked per program run, the [tt]%subs[/tt] will be redefined at each file type and the values for the former ones will be lost.
Also if the checking routines are all the same for all file types, you can put them in a separate module that will be [tt]require[/tt]'d by each [tt]%subs[/tt] file (multiple requires of the same file are silently bypassed by perl).

prex1
: Online tools for structural design
: Magnetic brakes for fun rides
: Air bearing pads
 
Kevin,
The valuable info from this post should be condensed and added to FAQ area on this site.
 
Or should I stick to if/elsif in which case the program becomes much more entangled?

I honestly think you are confusing yourself. I simply do not understand why you think that will be worse than what you are contemplatting. In my opinion, it will be better.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top