On Tue, Sep 29, 2009 at 03:49:31PM +0200, Christoph Bussenius wrote:
: Hi,
:
: I read is S03,
:
: The && and || operators are smarter about list context and return ()
: on failure in list context rather than Bool::False. The operators
: still short-circuit, but if either operator would return a false
: value, it is converted to the null list in list context so that the
: false results are self-deleting.
:
: For "&&", wouldn't it be a better idea to return an empty list only if
: the *first* operand is false? In other words, I suggest that "$a && $b"
: behave in list context like this:
:
: * If $a is false, return ()
: * Otherwise, return $b
:
: Here's a use case that would benefit from this behaviour:
:
: Suppose you want to generate an argument list for an external command.
: For some reason you have a boolean value $include_arg3 and you want to
: include $arg3 only if $include_arg3 is true:
:
:my @args = $arg1, $arg2, $include_arg3 && $arg3, $arg4;
:
: Here you probably want to include $arg3 even if it is a false value like
: "0", provided that $include_arg3 is true.
Hmm, well, I see your point, but there are some arguments for the current
behavior as well:
* Changing && without changing || would introduce a strange asymmetry.
* Changing && to be pure conditional kinda undoes the list associative
meaning of 'return the first false value or the last value'.
* It would imply propagating list context to the left side but not
the right side, which is time-travelishly problematic in a
lazy language.
* Alternately, it would mean that the result would have to be marked
as to whether it came from the left or the right so that binding
into a list context would know whether to throw it away or not.
* Or one could return Nil instead of the left value, but then you
lose any interesting value of false.
* If one wants it to mean
my @args = $arg1, $arg2, ($arg3 if $include_arg3), $arg4;
one can write it that way, since C already knows it's about
control flow, not data selection, and returns Nil on false. Or
you can write:
my @args = $arg1, $arg2, (if $include_arg3 {$arg3}), $arg4;
if you want them in the other order.
* If you know you're generating *positional* arguments ahead
of time, you probably don't want list processing anyway; you
probably want to put the args into a parcel/capture anyway to
delay the application of context until binding time:
my $args = \($arg1, $arg2, $include_arg3 && $arg3, $arg4);
In this case the result of the && is its own parcel/capture
that waits until binding time to decide how to behave.
But I agree that it's a trap of sorts. My gut feeling is that it
won't happen often enough to become a FAQ, but I could be wrong.
Larry