The perils of Perl 5's indirect object syntax
Perl lets you call object methods in two different ways:
- $obj->method()
- method $obj
It's funny that Max posted that blog entry the other day, because I just was shown a problem that was caused indirectly by it. Mike O'Regan showed me some code that he was surprised even compiled, because it certainly wasn't working.
sub custom_sort {
return
$a->{foo} cmp $b->{foo}
||
a$->{bar} cmp b$->{bar}
}
See the a$ instead of $a? Yuck. But it compiles just fine. Why? Well, let's see what B::Deparse decompiles it out as:
$ perl -MO=Deparse foo.pl
sub custom_sort {
return $$a{'foo'} cmp $$b{'foo'} || $-->a > {'bar'} cmp $-->b > {'bar'};
}
foo.pl syntax OK
Turns out that it's calling method a on the object $- and then seeing if that is greater than {'bar'}. Double-ugh.
Perl 6 still has indirect object syntax, but you must follow it with a colon, as in method $obj: @args. Larry says in Perl 6 it's completely unambiguous.
Categories:
0 TrackBacks
Listed below are links to blogs that reference this entry: The perils of Perl 5's indirect object syntax.
TrackBack URL for this entry: http://perlbuzz.com/cgi-bin/mt/mt-tb.cgi/318
With strict or warnings, the error would have been fairly obvious, though.
With strict:
$ perl -MO=Deparse -Mstrict foo.pl Bareword "bar" not allowed while "strict subs" in use at foo.pl line 3. Bareword "bar" not allowed while "strict subs" in use at foo.pl line 3. foo.pl had compilation errors. sub custom_sort { use strict 'refs'; return $$a{'foo'} cmp $$b{'foo'} || $-->a > {'bar'} cmp $-->b > {'bar'}; }Without strict, but with -w:
$ perl -MO=Deparse -w foo.pl Unquoted string "bar" may clash with future reserved word at foo.pl line 5. Unquoted string "bar" may clash with future reserved word at foo.pl line 5. Name "main::b" used only once: possible typo at foo.pl line 3. Name "main::a" used only once: possible typo at foo.pl line 3. BEGIN { $^W = 1; } sub custom_sort { return $$a{'foo'} cmp $$b{'foo'} || $-->a > {'bar'} cmp $-->b > {'bar'}; } foo.pl syntax OKWow, yeah, that's a perfect example of how these sorts of things add complexity and make it hard to parse Perl. :-) I was looking for a good example, but with some of these weird edge cases it can be really hard to come up with something unless you're an old-time perlguts hacker. :-)
-Max
Here is another, real-life example (typo I just did a couple of days ago and was wondering about the error message) : I typed curly braces instead of parentheses in
my @list = qw/foo bar/; map {foobar{$_}} @listand got that strange message
because this is parsed as