Re: Dereferencing code refs with & vs. ->()
by merlyn (Sage) on Sep 22, 2005 at 23:44 UTC
|
The arrow form wasn't added until 5.004, between release-candidate-1 and release-candidate-2, on a bet. And I won the bet.
So, if you're looking at ancient documentation, you'll see &$coderef instead of the modern arrow form.
| [reply] [d/l] |
|
|
Haha, that's hilarious. I'm glad you won. :)
| [reply] |
Re: Dereferencing code refs with & vs. ->()
by jkeenan1 (Deacon) on Sep 23, 2005 at 01:07 UTC
|
doran wrote:
I prefer the former, since that's the way I'm used to dereferencing other things.
Yes, you and most everybody else. I've rarely seen the & version in the last five years.
But just about all examples I see use the '&' prefix instead of the arrow operator.
Really? Where are those examples? In books dating from 1998?
FWIW, TheDamian recommends the arrow form in Perl Best Practices. So, if nothing else, lots of other Perl programmers will understand what you're doing.
And that's what's most important.
Jim Keenan | [reply] |
|
|
| [reply] |
Re: Dereferencing code refs with & vs. ->()
by Fletch (Bishop) on Sep 23, 2005 at 02:30 UTC
|
About the only place you'd need the ampersand version is if you're trying to get the current scope's @_ passed a la &somesub;. But that's really rare.
| [reply] [d/l] [select] |
|
|
Or anytime you're talking about a named subroutine (my $bar = \&foo;) or using the GOTO &SUB form (goto &$bar;). There's still a few places that it's required. Another reason to use the ampersand version is to disable prototype checking, for those subroutines that are evil enough to use it without good reason.
My criteria for good software:
- Does it work?
- Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
| [reply] [d/l] [select] |
|
|
The use of &foo in \&foo has nothing to do with dereferencing. You're not calling foo.
Also, in goto &$bar; you aren't derefencing - it's the magical goto that jumps to the subroutine pointed to by $bar. If you were derefencing, you'd jump to the label that was returned by &$bar;. And that's what's happening if you do goto $bar->();. Or goto &$bar();.
Another reason to use the ampersand version is to disable prototype checking, for those subroutines that are evil enough to use it without good reason.
But that's a difference between foo() and &foo(). Again, that has nothing to do with dereferencing. It can't even do prototype checking when doing dereferencing, as prototype checking is done at compile time. The following code runs without errors - despite violent prototype violations:
!/usr/bin/perl
use strict;
use warnings;
my $ref = sub ($) {print "Hello, world\n"};
&$ref();
$ref->();
__END__
Neither the &$ref();, nor the $ref->(); is checked for its prototype. | [reply] [d/l] |
|
|
|
|
Re: Dereferencing code refs with & vs. ->()
by ambrus (Abbot) on Sep 23, 2005 at 15:48 UTC
|
I think it's mostly a question of style.
The &-thingy has the disadvantage that beginners leave out the parentheses and wonder why the subroutine gets the arguments of its parents; otoh this is an advantage too, because you can't do the same with the arrow notation (and you can't do goto &$sub with arrows either). The arrow notation can sometimes be shorter, because you may not need the braces around an expression, or you might even leave out the arrow in newer versions of perl, for example:
perl -we '$op{"+"} = sub { $_[0] + $_[1] }; $op{"-"} = sub { $_[0] - $
+_[1] }; print $op{$ARGV[1]}($ARGV[0], $ARGV[2]), $/;' 8 - 2
Otoh, when you do need parentheses around the expression generating the function, the ampersand-notation is shorter.
Other than these minor points, the difference is aesthetiyc. I always use the ampersand notation, moreover, I never use the arrow for dereferencing either an array or a hash or a code. I do use the arrow for method calls of course. (This style is new, it wasn't like this in my earlier scripts.)
| [reply] [d/l] [select] |
Re: Dereferencing code refs with & vs. ->()
by pg (Canon) on Sep 23, 2005 at 01:12 UTC
|
"I prefer the former, since that's the way I'm used to dereferencing other things."
You don't actually use -> to de-referencing, you use it to access a member of a collection. When you dereference a hash or an array, you will use @ and %. In this sense, &$thingy holds more consistancy there.
-> fits well with class method, as class can be viewed as a collection of properties and methods.
| [reply] |
|
|
You don't actually use -> to de-referencing, you use it access a member of a collection.
No, you use {} and [] to access a member of a collection. You use -> to dereference references. That's why it is called a "dereference operator" in perlop. (Specifically, it's called an "infix dereference operator" which helps to describe the syntax.)
Update: I imagine your confusion stems from the fact that it must be used in conjunction with {}, [], or () in order to be useful. (Hence "infix" btw.) Still, it's doing the same job as the leading dollar sign ($) in $$thingy[0].
-sauoq
"My two cents aren't worth a dime.";
| [reply] [d/l] [select] |
Re: Dereferencing code refs with & vs. ->()
by Anonymous Monk on Sep 23, 2005 at 09:08 UTC
|
To address the actual question, the advantage of using $ref -> () instead of &$ref() is that the former obeys the strict references pragma and the latter will generate an error when using strict references. | [reply] |
|
|
| [reply] |
|
|
#!/usr/bin/perl
use strict;
use warnings;
my $ref = sub {print "Hello, world\n"};
$ref->();
&$ref(); # Look ma, I am using strict!
__END__
Hello, world
Hello, world
But:
#!/usr/bin/perl
use strict;
use warnings;
sub hello {print "Hello, world\n"};
my $ref = "hello";
$ref->();
__END__
Can't use string ("hello") as a subroutine ref while "strict refs" in
+use
| [reply] [d/l] [select] |
|
|
Maybe you could have said something more civil than "bullshit"? Politeness is free, and the payback is large, try it, you might like it.
---
$world=~s/war/peace/g
| [reply] |
A reply falls below the community's threshold of quality. You may see it by logging in.
|
Re: Dereferencing code refs with & vs. ->()
by Anonymous Monk on Sep 23, 2005 at 10:08 UTC
|
I prefer &$thingy over $thingy->(). It's one character less (three less if you're not passing arguments), and it's more general. This works:
&{ Block returning a code reference }
but this doesn't:
{ Block returning a code reference }->();
That's why I also prefer:
$$hash_ref{key} = $$array_ref[1];
over
$hash_ref->{key} = $array_ref->[1];
-> is not a shortcut. It's a detour ;-) | [reply] [d/l] [select] |
|
|
sub t {
my $sub=shift;
$sub->();
}
sub u {
my $sub=shift;
&$sub;
}
t(sub{print">@_<"},1,2,3,4,5);
u(sub{print">@_<"},1,2,3,4,5);
_END__
><
>1 2 3 4 5<
It's one character less (three less if you're not passing arguments), and it's more general.
More general? Im not sure I agree with that... And im not convinced about the one character less either. Id say that for the below its actually one character more. Especially given the above point that &{EXPR}() is the equivelent of EXPR->() and not &{EXPR}
do { sub { print 'foo' } }->();
( sub { print 'bar' } )->();
That's why I also prefer:$$hash_ref{key} = $$array_ref[1];
I class that notational style as a code smell. If I have to deal with code like that the first thing I do is switch it to use the infix dereference operator. And strangely I often find that the bug I was looking for just vanishes by doing so. IOW: this style is error prone and IMO a maintenance nightmare.
---
$world=~s/war/peace/g
| [reply] [d/l] [select] |
|
|
&{do {
# stuff here
sub { ... };
}};
Because I'm not sure I like that syntax. It looks very obfuscated, to my eyes.
$$hash_ref{key} = $$array_ref[1];
Yes, I see that a lot in older code. The problem is that this syntax only works because of how tightly $ binds vs. {} or []. You're depending on the Perl parser always guessing correctly. Maybe I'm paranoid, but I prefer not making the parser guess my intention.
My criteria for good software:
- Does it work?
- Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
| [reply] [d/l] [select] |
|
|
The official way of coding that is:
${$hash_ref}{key} = ${$array_ref}[1];
You may leave of the braces if the content of the block is a simple variable. Perhaps you find that obfuscated, but that's actually the same rule as the first (optional) argument of print. The file handle is passed as a block, and taken as the result, but if the block is a simple variable, you may leave off the braces. If that isn't obfuscated, why is the code I presented obfuscated? Or is it that you aren't used to it, and call anything you aren't used to obfuscated?
If you want to take a slice of a hash or an array, and all you have is a reference to it, how do you do it without being "obfuscated"? I write it as:
@$hash_ref{$key1, $key2, $key3};
which follows naturally from accessing a single value:
$$hash_ref{$key1};
But
@hash_ref->{$key1, $key2, $key3};
doesn't work and nor does
$hash_ref->{$key1, $key2, $key3};
And no, my code isn't littered with
&{do {... sub {...}}};
| [reply] [d/l] [select] |
|
|
{ Block returning a code reference }->(); doesn't work, but ( Block returning a code reference )->(); works, doesn't it?
Also &$thingy calls the subroutine with the same @_, so it's not the same as $thingy->(), this latter is really equivalent to &$thingy(). I think you probably thought of &$thingy() anyway, as that's what's one character less than $thingy->().
| [reply] [d/l] [select] |