The proper way to open()
Smylers at stripey.com
Wed Feb 1 13:34:05 GMT 2012
Yitzchak Scott-Thoennes writes:
> On Mon, Jan 30, 2012 at 9:12 AM, David Cantrell
> <david at cantrell.org.uk> wrote:
> > On Mon, Jan 30, 2012 at 05:03:47PM +0000, James Laver wrote:
> > > On 30 Jan 2012, at 16:56, Dominic Thoreau wrote:
> > >
> > > > open IN, '<', $cfg || handle_that_error_sub;
> > >
> > > No, explicitly not. The || operator is far too high precedence
> > > binding. Use 'or' to remove your bug.
> > No. The correct solution to buggy code caused by precedence is not
> > to invent a new level of precedence, but to use parens.
That makes sense if you see the problem as being one of precedence.
Until I started using Perl I'd only ever seen an OR operator (however
spelt) used for combining boolean expressions, such as:
if (!$awoke || $booted > $awoke)
The concept of 'or if that command failed, here's what to do instead'
was new to me. I liked it, and that there was an operator for it.
That the two operators are in some situations interchangeable was
slightly surprising to me at first, and in my mind doesn't seem like a
reason to start trying to interchange them. (Similarly there are some
situations where you could get away with using | instead of ||, but I
don't think it's a good idea.)
And each of the Perl operators || and or has a precedence level that
means in many (even most?) circumstances it does the right thing which
means that generally I find not thinking much about precedence.
In particular, I don't look at a situation where OR behaviour is
required and consider what precedence level is needed then pick || or or
as appropriate. But I can see that if you do think like that, then
picking an OR operator of appropriate precedence is a tedious step to go
through, and using parens as a generic tool for curing all precedence
issues seems much cleaner.
To me the above open line doesn't look like a precedence issue, but
using an operator in a way which doesn't fit. That the two operators
happen to be different precedence variants of each other is an
implementation detail, and that one can always be achieved with t'other
doesn't seem a reason to avoid it any more than it would be to avoid ||
because that Mr De Morgan showed it can be implemented with a
combination of ! and &&.
> > I do realise that it was the p5p gang who invented the new level of
> > precedence, but that doesn't mean you should play along.
The sentiment of not blindly using a feature just because at some point
it got added to core Perl sounds most sensible to me.
Please can we get out of the habit of beginning follow-ups with "No"?
That's 3 in a row following back through the nesting here, mostly for
things which are matters of opinion and taste, not fact.
It turns out that Dave and I happen to think about this situation
differently, but that doesn't mean I consider him to be wrong for
thinking the way he does (which is perfectly consistent and obviously
works for him). Surely we can share different opinions on a topic
without labelling each other as being wrong? It just seems a little
> Use or for flow control and you won't find yourself fighting against
> Perl. Reserve use of || for non-flow control. (For the pedants, I
> define flow control as the operation being in void context or an
> argument to a flow control and/or operation.)
So I'm doing the same as you, but that description doesn't match how I
decide whether to use || or or: quite simply I don't, any more than I
decide whether to use || or % or << or cmp or -e any other operator in a
given situation; to me they seem like two entirely separate operators
for separate purposes, so in selecting the operator for a task I don't
first narrow it down to an OR-like operator then pick between them.
> Or always use parens with builtins. Some people advocate that anyway,
> but I don't care for it.
I find avoiding unnecessary parens on built-in functions and functions
imported from modules is useful for catching typos (or forgetting to use
a module). It also provides a kind of documentation when reading the
code, hinting that it's a function defined elsewhere not in the current
And in general I find avoiding unnecessary parens is good, cos it means
when I do have parens there are fewer of them, so it's easier to see at
a glance how they match, and they are a hint that the normal precedence
levels are being overridden. Whereas if you often have unnecessary
parens scattered through the code then you're used to seeing them even
when operators are operating at their normal precedences, and it can be
harder to spot when that's been altered.
However ... this does mean I get caught out by things like:
my $result = process +(munge $input), $limit;
where I forget the + sign.
If I'd wanted to only pass some of the terms to the outer function call
I would've indicated it with parens like this, where it's quite clear
that everything inside the parens happens before anything outside:
my $result = (process munge $input), $limit;
I find it odd that placing the opening paren after the function name
makes it behave as though it were before, rather than just changing the
precedence of the terms the parens enclose. (See above comment about
core Perl features.)
So I can see why somebody would choose to adopt the opposite policy of
always using parens with all functions, to avoid this trap.
More information about the london.pm