Re: What's so bad about &function(...)?
by tirwhan (Abbot) on Dec 07, 2005 at 18:16 UTC
|
(As read in Perl Best Practices): The ampersand is ambiguous and can be interpreted by perl as bitwise AND in certain contexts. Since it is not necessary, it is better to always omit the &.
Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it. -- Brian W. Kernighan
| [reply] |
|
The ampersand is ambiguous and can be interpreted by perl as bitwise AND in certain contexts.
Wow, I've never seen that trap sprung.
The trap I have seen sprung quite a few times is sub log { ... }. That is why I follow my own advice in my 'classic' node, (tye)Re: A question of style, and mix case in all of my subroutine names.
But, I sometimes slip and use camelCase and then get lazy and give a routine or two one-word names and... I've actually still been bit by sub log { ... }, just less frequently than before.
So using &func( ... ) is still in my list of optional best practices for two reasons. First, it prevents you from being caught (often very confusingly) if you unintentially give your subroutine a "reserved" name. Second, it is a valid style choice to visually distinguish user sub calls from other similar-looking constructs.
Note that if you import a &log, then log() will call it and so the leading ampersand is not as useful for imported routines. So I don't find the "might disable prototypes" argument too worrisome. Since, if I didn't important the routine, then I'm sure to know whether or not I was stupid enough to use a prototype on it. While, if I imported the routine, I don't need to use the ampersand (and modules that export over the top of built-in functions usually have a good reason for doing so or get bug reports filed against them).
Now, as far as best practices go, I consider "always mix case (or add an underscore) in your subroutine names" to be a better "best practices" then "use &sub(...) when calling your own subs", because there are fewer nearby potential down-sides (such as using &sub w/o parens). But I do get annoyed when I see (every time the subject comes up) a bunch of people spouting poorly justified proclamations against using &sub(...) while also not warning against using subroutine names that might accidentally match a built-in.
| [reply] [d/l] [select] |
|
The ampersand is ambiguous and can be interpreted by perl as bitwise AND in certain contexts. Since it is not necessary, it is better to always omit the &.
Sounds profound, and it got you quite some XP. It should have been negative XP, because your conclusion is 100% wrong.
If you you are afraid to get be bitten by the ambiguity you mention, you should avoid using bitwise and, not the sub-sigil. Because whenever perl has the option to parse an ampersand as a sub-sigil or as a bitwise and, it will parse it as the sub-sigil.
$ perl -MO=Deparse,-p -e 'sub foo {} sub bar {} bar & foo()'
sub foo {
}
sub bar {
}
bar(&foo());
-e syntax OK
Someone using sub-sigils in the above case would have gotten the binary and parsing:
perl -MO=Deparse,-p -e 'sub foo {} sub bar {} &bar & &foo()'
sub foo {
}
sub bar {
}
(&bar & &foo());
So, you have two options to avoid this ambiguity: either avoid using binary and, or to always use the sub-sigil.
| [reply] [d/l] [select] |
Re: What's so bad about &function(...)?
by Ovid (Cardinal) on Dec 07, 2005 at 18:15 UTC
|
Because if beginnners are going to stick with simple code (which is fine) they should be sticking with simple code which doesn't run the risk of mysterious side effects (which is not fine).
| [reply] |
|
What is the mysterious side effect of using a leading ampersand? The only side effect I can think of, off the top of my head, is that it avoids prototypes, and prototypes, I would expect, are outside the realm of "simple code".
| [reply] |
|
Yes, but not everyone programs in a vacuum. Sooner or later they'll start using code which does have prototypes. Imagine, for example, that they start using Test::More. Those functions all have prototypes and using the leading ampersand is sure to bring them woe. Imagine, for example, typing "is" instead of "ok":
&is(some_func(3,4));
The prototype is now disabled so they don't get the compile-time failure telling them that the test function has been called incorrectly. If you're new to testing or that's buried in bunch of other tests, it can be quite difficult to figure out.
| [reply] [d/l] |
|
|
|
|
|
|
If you don't specify arguments, it passes any existing @_.
#!/usr/bin/perl
use strict;
use warnings;
yes_ampersand("yes\n");
no_ampersand("no\n");
sub foo {
print $_[0];
}
sub yes_ampersand {
print $_[0];
&foo;
}
sub no_ampersand {
print $_[0];
foo;
}
Here's the output:
yes
yes
no
Use of uninitialized value in print at ampersands.plx line 9.
| [reply] [d/l] [select] |
|
|
|
Re: What's so bad about &function(...)?
by Limbic~Region (Chancellor) on Dec 07, 2005 at 18:17 UTC
|
japhy,
I think it is half cargo-culting the mantra where the difference between &sub and &sub() is unknown by the chanter and half a good rule of thumb. You can't get bitten by a confusing @_ or circumvented prototype if you avoid using a preceding & all together.
| [reply] [d/l] [select] |
Re: What's so bad about &function(...)?
by jdporter (Paladin) on Dec 07, 2005 at 18:32 UTC
|
For the same reason we don't recommend writing @{\@foo} when @foo works just as well.
:-)
We're building the house of the future together.
| [reply] [d/l] [select] |
|
That reminds me of a question I like to use for teaching intermediate-level perlers:
What is the difference between @{\@foo} and @{[@foo]}?
I think it makes a good interview question, too.
I don't think it is really the same reason at all. The reference/dereference cycle in your example is real, but insignificant, while the & sigil is usually optional but sometimes affects perl parsing and compilation. Ovid and tirwhan covered the traps nicely.
| [reply] [d/l] [select] |
|
| [reply] |
|
|
What is the difference between @{\@foo} and @{@foo}?
Um... they're both the wrong way to write @foo, but the second one's more inefficient, but caring excessively about efficiency of bad code that you should refactor anyway is a premature optimization, so ... umm... it's a trick question, with the answer of "There's no difference; you'ld never use either one in production code?"
Do I win? :-) Or did I miss something subtle? :-(
| [reply] |
|
|
|
|
|
|
Re: What's so bad about &function(...)?
by revdiablo (Prior) on Dec 07, 2005 at 21:28 UTC
|
My main objection is cosmetic. I think using the & is ugly. Specifically, I think it's yet another piece of unnecessary syntax. I try to minimize unnecessary syntax as much as possible. It's the same reason I omit parentheses under cases where they're not needed for either precedence or clarity.
| [reply] [d/l] |
|
It's the same reason I omit parentheses under cases where they're not needed for either precedence or clarity.
Then you're forcing the maintainers to memorize an operator precedence table to infer your meaning, instead of writing it explictly. At the time you write you code, you know exactly what you mean, and where the parens must go, but you then take away this information in order to promote "consiseness". This is, in my experience, where mistakes tend to happen. I don't think the risk is worth the gain.
For one thing, I don't think it's worth it to do that much work in stripping down my code. Whenever I find that I've really got too many layers of parens, then I've always found that my code itself is too complex; so I simplify it, or break it into sub-expressions.
For me, it's all about minimizing the time spent proving the code is correct; if I have to spend time pulling up an obscure table in my memory and cross checking it, there's a chance I'll fuck it up, especially if I'm sick, over-tired, or hungry. Worse yet, I have to carefully cross check code any code that doesn't include parens (and look up that damned table(!)), because I don't know if you were sick, tired, or hungry when you wrote the code, so I don't know if you intended the odd precedence the code may happen to be running with, or if it's a horrible mistake. An explict encoding (and decent comments!) correct both problems.
Do whatever works best for you, but in my experience, minimizing the number of things I have to think about to get the code right leads to fewer mistakes, and fewer bugfixes six months after I've forgotten about the project and what it's all about.
--
Ytrew
| [reply] |
|
| [reply] |
|
|
Re: What's so bad about &function(...)?
by Roy Johnson (Monsignor) on Dec 07, 2005 at 21:45 UTC
|
| [reply] |
Re: What's so bad about &function(...)?
by zentara (Archbishop) on Dec 08, 2005 at 13:38 UTC
|
It gets further complicated by the widely used references to subs, which contain ampersands, and is never critisized.
$window->signal_connect( 'destroy' => \&delete_event );
I'm not really a human, but I play one on earth.
flash japh
| [reply] [d/l] |
|
| [reply] |
Re: What's so bad about &function(...)?
by Siddartha (Curate) on Dec 09, 2005 at 17:03 UTC
|
In the end it doesn't really matter. Like almost anything in Perl you can do it in more than one way. If you know the pitfalls with all the different options then good for you. Use whatever you want.
The fact remains though that for someone new to Perl using &foo could pose a lot more problems than not using it, so to make it easier for beginners not to walk into problems they are not aware of, rather leave it out in the code submitted here.
If they know enough about perl and read discussions like this one then they can decide to use whatever they want but be aware of the consequences.
Just my opinion. | [reply] |
|
Another reason it doesn't much matter is that, to make things more consistent, we're changing what it means in Perl 6. The notation no longer has anything to do with how the arguments are processed--there are now flattening operators for that. Instead, when you say &foo, you're explicitly marking "foo" as a noun rather than a verb. As a noun, it always returns a scalar reference in scalar context, and like any other reference, it is not dereferenced unless you do so explicitly. In the case of &foo, it is not called unless you say &foo() or some such.
Interestingly, this completely removes the Perl 5 distinction between foo(1,2,3) and &foo(1,2,3). Those are handled identically in Perl 6. What changes is the meaning of bare &foo. You now always have to pass @_ explicitly if that's what you mean.
| [reply] |
|
In Perl5, if you have arguments to a function, the parenthesis are optional if you don't use the & sigil (unless of course they are needed to prevent misparsing). However, if you use &foo to call a sub, and you want to call it with arguments, the parenthesis are mandatory.
Will you be able to do:
&foo 1, 2, 3
in Perl6?
| [reply] [d/l] |
|