The problem is that you did:
for $x (this ? (...) : "") {
# code that modifies $x
}
When this is false, $x does not get assigned the value "", but rather is aliased to it. And you can't change "" since it's a constant string.
_____________________________________________________
Jeff[japhy]Pinyan:
Perl,
regex,
and perl
hacker.
s++=END;++y(;-P)}y js++=;shajsj<++y(p-q)}?print:??; | [reply] [Watch: Dir/Any] [d/l] |
F:\dev\vladb>perl -MO=Deparse readonly.pl
Can't call method "PADLIST" on an undefined value at C:/Perl/lib/B/Dep
+arse.pm li
ne 1039.
CHECK failed--call queue aborted.
And now an attempt an an explanation.
perlsyn explains this well, but is going on when $path_list is the empty string (""),
what your *ugly* code breaks down to is foreach my $some_path ( (defined $path_list &&
$#$path_list >= 0)
? @{$path_list} : "" ) {
clean_path($some_path); # $some_path is now ""
## i'd rewrite it as
foreach my $some_path ( (defined $path_list and
ref($path_list) eq 'ARRAY'
and scalar @{$path_list} )
? @{$path_list} : '') {
anyway, as I was saying, you ought to check if $path_list is a reference to an ARRAY, and if it's not, you ought to return one([] what I meant was, undef, or (), or maybe even @{[]}, but definetly not '', hopefullly you get the picture) instead of the empty string(""), because what happens is the same thing I demonstrate with the following one line perl -e"for my $orK(1,2,3,4) { $orK =~ s/.//g; } " which would also throw the read-only error. Why, because (1,2,3,$foo,$4) is not a data structure (an array). It is a list. The for loop implies list context. And since it is not an array, $orK, which becomes the alias for each element of the list, points to hard coded members of a list, which are read only. The following perl -e"@f=qw,1 2 3 4,;for my $orK(@f){ $orK =~ s/.//g; }" gets no read-only error. Why? cause $orK becomes an alias for each member of the list, which in this case is a reference to $f[0] which is a data structure. Its pretty much the same as perl -e"@f=qw,1 2 3 4,;for my $orK($f[0],$f[1],$f[2],$f[3]){ $orK =~ s/.//g; }"
That's it. Try it out, read perlsyn again, read japhys excellent context tutorial (List is a 4 letter word, it's on his website, link to which is on his homenode).
I'm done.
| [reply] [Watch: Dir/Any] [d/l] [select] |
Thanks tons ;-)).
Yeah, again, as I mentioned this was an old code, therefore it's *ugly* ;-(. I would try to avoid such code from now onwards.
Thanks all for your comments. $path_list is actually always an ARRAY reference (although, it's hardly obvious from the code ;-); therefore, I went into the trouble of checking whether it contained any elements and if not I simply made sure that the loop would run at least once (with $some_path set to ""). Frankly, I never knew that $some_path was just an 'alias' to the value. THat's definitely new to me hehe. However, the code doesn't break when there's at least 1 element in the array pointed to by the $path_list scalar. That's where I was confused...
"There is no system but GNU, and Linux is one of its kernels." -- Confession of Faith
|
| [reply] [Watch: Dir/Any] |
Ick at the $#_, that is shocking coding when you can write:
foreach (@_) {
# use $_ here
}
And what's wrong with:foreach my $some_path (@$path_list) {
# etc
}
Have you looked into using File::Spec (standard with Perl I think). I think using canonpath and/or no_upwards might do what you're looking for in an easier to maintain and more portable manner.
Hope this helps...
gav^ | [reply] [Watch: Dir/Any] [d/l] [select] |
While the other posters have focused on your direct problem and on your poor code flow. I'm wondering about your question of checking the readonlyness of a variable. My best stab is this:
sub is_readonly {
eval {my $save=$_[0]; $_[0]=42; $_[0]=$save;};
return $@ =~/read.?only/;
}
Can anybody come up with a cleaner way?
TACCTGTTTGAGTGTAACAATCATTCGCTCGGTGTATCCATCTTTG
ACACAATGAATCTTTGACTCGAACAATCGTTCGGTCGCTCCGACGC | [reply] [Watch: Dir/Any] [d/l] |
I've talked about the Scalar::Util module before, and once again it comes to the rescue!
use Scalar::Util qw(readonly);
...
if (readonly $x) {
...
}
Get used to Scalar::Util and List::Util now - they're standard modules in 5.8. | [reply] [Watch: Dir/Any] [d/l] |
sub is_readonly {
eval {my $save=$_[0]; $_[0]=$save;};
return $@ =~/read.?only/;
}
Scalar::Util did not work for me. | [reply] [Watch: Dir/Any] [d/l] |
Scalar::Util did not work for me
I would expect Scalar::Util to perform the task flawlessly.
Could you provide an example script that demonstrates its failing ?
Cheers, Rob
| [reply] [Watch: Dir/Any] |
I'm not sure if your $some_path variable is a string or an array but the problem likely stems from failing to provide the clean_path function with a reference (so that you could modify the var in the function).
metadoktor
"The doktor is in." | [reply] [Watch: Dir/Any] |