<?xml version="1.0" encoding="windows-1252"?>
<node id="564792" title="Secret Perl Operators: the boolean list squash operator, x!!" created="2006-07-31 12:30:46" updated="2006-07-31 08:30:46">
<type id="120">
perlmeditation</type>
<author id="114691">
Aristotle</author>
<data>
<field name="doctext">
&lt;h2&gt;I feel like a broken record&lt;/h2&gt;

&lt;p&gt;Are you like me, and often find yourself wanting to include an element in a list conditionally (often depending on whether it is defined)?&lt;/p&gt;

&lt;p&gt;F.ex., I may want to construct a URI which has a number of moving parts.&lt;/p&gt;

&lt;ul&gt;

&lt;li&gt;In the simplest case, it may look like &lt;tt&gt;http://example.net/app/doc&lt;/tt&gt;, where &lt;tt&gt;doc&lt;/tt&gt; is a controller in the web app.&lt;/li&gt;

&lt;li&gt;To link a specific item, the URI might be &lt;tt&gt;http://example.net/app/doc/42&lt;/tt&gt;&lt;/li&gt;

&lt;li&gt;Some controllers are broken down further, giving things like &lt;tt&gt;http://example.net/app/doc/42/notes&lt;/tt&gt;&lt;/li&gt;

&lt;li&gt;The app supports multiple sites, so I might also have something like &lt;tt&gt;http://example.net/app/joebob/doc&lt;/tt&gt;&lt;/li&gt;

&lt;li&gt;To get the editing interface, you need to prefix the whole shebang accordingly, ie. for the &lt;tt&gt;joebob&lt;/tt&gt; subsite: &lt;tt&gt;http://example.net/app/admin/joebob/doc&lt;/tt&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;There are two dead obvious approaches to write this in Perl:&lt;/p&gt;

&lt;readmore&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The ugly [doc://push]-based version:&lt;/p&gt;
&lt;c&gt;
my   @part = ( 'http://example.net/app' );
push @part, 'admin'  if $is_admin_link;
push @part, $subsite if defined $subsite;
push @part, $mode;
push @part, $id      if defined $id;
push @part, $submode if defined $submode;

my $uri = join '/', @parts;
&lt;/c&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The nicer approach with a ternary:&lt;/p&gt;
&lt;c&gt;
# [updated: originally had `'admin' ? $is_admin_link : ()`]

my @part = (
	'http://example.net/app',
	( $is_admin_link   ? 'admin'  : () ),
	( defined $subsite ? $subsite : () ),
	$mode,
	( defined $id      ? $id      : () ),
	( defined $submode ? $submode : () ),
);

my $uri = join '/', @part;
&lt;/c&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But both approaches require you to repeat yourself unncessarily. In the [doc://push] case, you have to repeat the &lt;tt&gt;push @part&lt;/tt&gt; bit, and in the ternary case, you have to supply &lt;tt&gt;: ()&lt;/tt&gt; as an &lt;i&gt;else&lt;/i&gt; clause for every case.&lt;/p&gt;

&lt;h2&gt;Enter &lt;tt&gt;x!!&lt;/tt&gt;&lt;/h2&gt;

&lt;p&gt;Obviously, this is a composite operator, consisting of &lt;tt&gt;x&lt;/tt&gt; and two &lt;tt&gt;!&lt;/tt&gt; negations.&lt;/p&gt;

&lt;p&gt;The double negation is there to forcibly convert the right side to a boolean value with the same truthness as the original value:&lt;/p&gt;

&lt;c&gt;
$a = undef;
print $a ? 'true' : 'false';  # prints 'false'
print $a;                     # prints '' and warns
$a = 0;
print $a ? 'true' : 'false';  # prints 'false'
print $a;                     # prints '0'
$a = 'abc';
print $a ? 'true' : 'false';  # prints 'true'
print $a;                     # prints 'abc'

# whereas

$a = undef;
print !!$a ? 'true' : 'false';  # prints 'false'
print !!$a;                     # prints '' without warning
$a = 0;
print !!$a ? 'true' : 'false';  # prints 'false'
print !!$a;                     # prints ''
$a = 'abc';
print !!$a ? 'true' : 'false';  # prints 'true'
print !!$a;                     # prints 1
&lt;/c&gt;

&lt;p&gt;So the &lt;tt&gt;!!&lt;/tt&gt; will force anything that shows up on the right side to be either &lt;tt&gt;1&lt;/tt&gt; or &lt;tt&gt;!1&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;tt&gt;x&lt;/tt&gt; is, of course, Perl’s repetition operator:&lt;/p&gt;

&lt;c&gt;
@_ = ( 'a' ) x 4;
print join ':', @_;  # prints 'a:a:a:a'
print scalar @_;     # prints '4'
&lt;/c&gt;

&lt;p&gt;Of interest to us are the cases where the number of repetitions is 1 or 0:&lt;/p&gt;

&lt;c&gt;
@_ = ( 'a' ) x 1;
print join ':', @_;  # prints 'a'
print scalar @_;     # prints '1'

@_ = ( 'a' ) x 0;
print join ':', @_;  # prints ''
print scalar @_;     # prints '0'
&lt;/c&gt;

&lt;p&gt;Since boolean values in Perl are either 1 or !1, that means &lt;tt&gt;( $something ) x $boolean&lt;/tt&gt; will do exactly what we want. And we can force everything to be a boolean using the &lt;tt&gt;!!&lt;/tt&gt; double negative. That is how we get &lt;tt&gt;x!!&lt;/tt&gt;.&lt;/p&gt;

&lt;ins&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; &lt;em&gt;caveat codor&lt;/em&gt; – as [ikegami] [id://564827|emphasises], the parens are &lt;strong&gt;required&lt;/strong&gt;! &lt;tt&gt;( $something ) x $boolean&lt;/tt&gt; does a very different thing from &lt;tt&gt;$something x $boolean&lt;/tt&gt;. I knew this, but forgot to harp on it. (Yes, this difference is too subtle. In Perl 6, there will therefore be two different operators, &lt;tt&gt;x&lt;/tt&gt; for strings and &lt;tt&gt;xx&lt;/tt&gt; for lists.)&lt;/p&gt;
&lt;/ins&gt;

&lt;p&gt;Bottom line: the example I gave can be written like this:&lt;/p&gt;

&lt;c&gt;
my @part = (
	'http://example.net/app',
	( 'admin'  ) x!! $is_admin_link,
	( $subsite ) x!! defined $subsite,
	$mode,
	( $id      ) x!! defined $id,
	( $submode ) x!! defined $submode,
);

my $uri = join '/', @parts;
&lt;/c&gt;

&lt;p&gt;Neato! Not only is it nicer, but I also find that &lt;tt&gt;x!!&lt;/tt&gt; has a beautifully evocative quality. &lt;tt&gt;:-)&lt;/tt&gt;&lt;/p&gt;

&lt;ins&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; but note that &lt;tt&gt;( $x ) x!! $cond&lt;/tt&gt; differs from &lt;tt&gt;$cond ? $x : ()&lt;/tt&gt; in shortcircuiting behaviour: the ternary will avoid evaluating &lt;tt&gt;$x&lt;/tt&gt; if &lt;tt&gt;$cond&lt;/tt&gt; is false, but &lt;tt&gt;x!!&lt;/tt&gt; will always evaluate it.&lt;/p&gt;
&lt;/ins&gt;

&lt;h2&gt;Conventional notes&lt;/h2&gt;

&lt;p&gt;You’ll notice that [doc://defined] always returns a boolean anyway, so the &lt;tt&gt;!!&lt;/tt&gt; isn’t actually necessary in three of our cases, and might not be necessary in the first one either.&lt;/p&gt;

&lt;p&gt;However, I find that one should use &lt;tt&gt;x!!&lt;/tt&gt; anyway, for two reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It documents intent. Using &lt;tt&gt;x!!&lt;/tt&gt; clearly signals that this is &lt;em&gt;not&lt;/em&gt; just a repetition.&lt;/li&gt;
&lt;li&gt;It protects you from errors. If the value of &lt;tt&gt;$is_admin_link&lt;/tt&gt; is 2 for some reason, it is still &lt;i&gt;true&lt;/i&gt; according to Perl, but in that case &lt;tt&gt;( 'admin' ) x $is_admin_link&lt;/tt&gt; (&lt;em&gt;without&lt;/em&gt; &lt;tt&gt;!!&lt;/tt&gt;) will yield a very different result from &lt;tt&gt;( 'admin' ) x!! $is_admin_link&lt;/tt&gt; (&lt;em&gt;with&lt;/em&gt; &lt;tt&gt;!!&lt;/tt&gt;).&lt;/li&gt;
&lt;/ol&gt;

&lt;/readmore&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;So there you have it. If you want to conditionally include a sub-list within a larger list, you can use the composite &lt;tt&gt;x!!&lt;/tt&gt; operator express exactly that.&lt;/p&gt;

&lt;p align="right" class="pmsig pmsig-114691"&gt;&lt;i&gt;Makeshifts last the longest.&lt;/i&gt;&lt;/p&gt;</field>
</data>
</node>
