Is there a more idiomatic way to do this?

A

Alan Mead

I recently created a script that did a lot of this sort of thing:

my $dataref = get_data($filename1) if ($condition==1);
my $dataref = get_data($filename2) if ($condition==2);

foreach my $datum (keys %$dataref) { ...

Which didn't raise an exception but $dataref was always nil. I had to
write:

my $dataref;
$dataref = get_data($filename1) if ($condition==1);
$dataref = get_data($filename2) if ($condition==2);

I'm not sure I understand precisely why the first one didn't work but
also failed to raise an error when run under the strict pragma. I
mean, if it was a scoping thing then shouldn't the reference to
%$dataref in the foreach loop trigger an exception?

Anyway, the second method fixed the problem but it's a bit ungainly. Is
there a more idiomatic way to do this?

Thanks,

-Alan
 
J

John W. Krahn

Alan said:
I recently created a script that did a lot of this sort of thing:

my $dataref = get_data($filename1) if ($condition==1);
my $dataref = get_data($filename2) if ($condition==2);

foreach my $datum (keys %$dataref) { ...

Which didn't raise an exception but $dataref was always nil. I had to
write:

my $dataref;
$dataref = get_data($filename1) if ($condition==1);
$dataref = get_data($filename2) if ($condition==2);

I'm not sure I understand precisely why the first one didn't work

It is explained in perlsyn.pod in the 'Statement Modifiers' section:

perldoc perlsyn
[snip]
NOTE: The behaviour of a "my" statement modified with a statement
modifier conditional or loop construct (e.g. "my $x if ...") is
undefined. The value of the "my" variable may be "undef", any
previously assigned value, or possibly anything else. Don't rely on
it. Future versions of perl might do something different from the
version of perl you try it out on. Here be dragons.

but
also failed to raise an error when run under the strict pragma. I
mean, if it was a scoping thing then shouldn't the reference to
%$dataref in the foreach loop trigger an exception?

No. As long as the argument to keys() is a hash it will not complain.

$ perl -le'use warnings;use strict; my $x; for ( keys %$x ) { print }'
$ perl -le'use warnings;use strict; my $x; for ( keys $x ) { print }'
Type of arg 1 to keys must be hash (not private variable) at -e line 1, near
"$x ) "
Execution of -e aborted due to compilation errors.
$ perl -le'use warnings;use strict; my $x; for ( keys @$x ) { print }'
Type of arg 1 to keys must be hash (not array dereference) at -e line 1, near
"$x ) "
Execution of -e aborted due to compilation errors.

Anyway, the second method fixed the problem but it's a bit ungainly. Is
there a more idiomatic way to do this?

Yes. Use an array for the filenames.


die "Range error for \$condition\n"
if $condition < 1 or $condition > @filenames;

my $dataref = get_data( $filenames[ $condition - 1 ] );




John
 
C

Chris Mattern

Alan said:
I recently created a script that did a lot of this sort of thing:

my $dataref = get_data($filename1) if ($condition==1);
my $dataref = get_data($filename2) if ($condition==2);

foreach my $datum (keys %$dataref) { ...

Which didn't raise an exception

Because you didn't use warnings. Don't do that.
but $dataref was always nil. I had to
write:

my $dataref;
$dataref = get_data($filename1) if ($condition==1);
$dataref = get_data($filename2) if ($condition==2);

I'm not sure I understand precisely why the first one didn't work

It didn't work because each time you used "my" you created
*another* lexical variable named "$dataref" which obscured
access to the previous ones.
but
also failed to raise an error when run under the strict pragma. I
mean, if it was a scoping thing then shouldn't the reference to
%$dataref in the foreach loop trigger an exception?

It will trigger a warning each time you declare a new $dataref if
you use warnings, which you should always do.
Anyway, the second method fixed the problem but it's a bit ungainly. Is
there a more idiomatic way to do this?

Not really. Normally, you would use "my" on the first assignment and
not the others, but since you can't be sure it'll execute, you have
to do it the way you laid out.
Thanks,

-Alan

--
Christopher Mattern

"Which one you figure tracked us?"
"The ugly one, sir."
"...Could you be more specific?"
 
B

Brian McCauley

Steve said:
my $dataref = '';

$files{$condition} and $dataref = get_data( $files{$condition} );

It is most certainly _less_ ideomatic to use the empty sting to
represent the concept of "this has no value" rather than to use the
special undefined value.
 
A

Alan Mead

I suppose a hash might be more perlish:

my %files = (
1 => 'filename1',
2 => 'filename2',
};

my $dataref = '';

$files{$condition} and $dataref = get_data( $files{$condition} );

$dataref or do_something_else;

Thanks to everyone for explaining the issue and offering suggestions. I
think I like the use of a list for integers but actually my conditions
would be better represented by strings so this hash idea is a good one.

-Alan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top