perl :"//" operator? - perl

I have a question about using "//" operator, my testing code is as following:
perl -e '#arr1=();#arr2=(1,2,3);#arr3=defined(#arr1)?#arr1:#arr2;print "[#arr3]\n"'
[1 2 3]
perl -e '#arr1=();#arr2=(1,2,3);#arr3=#arr1//#arr2;print "[#arr3]\n"'
[0]
perl -e '$v1=();$v2="123";$v3=defined($v1)?$v1:$v2;print "[$v3]\n"'
[123]
perl -e '$v1=();$v2="123";$v3=$v1//$v2;print "[$v3]\n"'
[123]
my question is, why do using "//" operator give the same results as using "defined()? : " on the scalar, but not array(or hash)?
Thanks!!!

Because the leftmost operand of ?:, ||, or && — or this newfanglulated // thingie — is always evaluated in boolean not list context, whereas the other operands inherit the surrounding context.
#a = #b && #c;
means
if (#b) {
#a = #c;
} else {
#a = scalar #b;
}
While
#a = #b || #c;
and also
#a = #b // #c;
both mean
means
if (#b) {
#a = scalar #b;
} else {
#a = #c;
}
The only way to get rid of the scalar in assigning #b to #a is to use ?:
#a = #b ? #b : #c;
which of course means
if (#b) {
#a = #b;
} else {
#a = #c;
}
There is also the property that ?: can be an lvalue:
(#a > #b ? #a : #b) = #c;
which of course means
if (#a > #b) {
#a = #c;
} else {
#b = #c;
}
EDIT
The implementation of #a // #b and its definition differ. Bug submitted. Thanks.

This has more to do with defined than with //. From perldoc -f defined:
Use of defined on aggregates (hashes and arrays) is deprecated. It used to report whether memory for that aggregate had ever been allocated. This behavior may disappear in future versions of Perl.
So in your first example, defined(#arr1) is false; in the second, defined(#arr1) is true, and #arr3 contains scalar(#arr1). The difference between // and defined($a) ? $a : $b is noted in perldoc perlop:
Although it has no direct equivalent in C, Perl's // operator is related to its C-style or. In fact, it's exactly the same as ||, except that it tests the left hand side's definedness instead of its truth. Thus, $a // $b is similar to defined($a) || $b (except that it returns the value of $a rather than the value of defined($a)) and yields the same result as defined($a) ? $a : $b (except that the ternary-operator form can be used as a lvalue, while $a // $b cannot). This is very useful for providing default values for variables. If you actually want to test if at least one of $a and $b is defined, use defined($a // $b).
(Emphasis mine.)
So for example:
(defined($a) ? $a : $b) = $c; # This is valid.
($a // $b) = $c; # This is not.

Related

Perl defined-or in a list context, why a scalar?

use strict;
use warnings;
use Test::More;
subtest 'explicit array' => sub {
my #row = (1,2,3);
# let's disassamble the array.
# without default it works:
my ($one, $two, $three) = #row;
is($one, 1, 'one');
# this works too:
($one, $two, $three) = #row ? #row : (10,20,30);
is($one, 1, 'one');
# and the default hits
my #emptyness;
($one, $two, $three) = #emptyness ? #emptyness : (10,20,30);
is($one, 10, 'one default');
# however, this squashes the array to a scalar
($one, $two, $three) = #row // (10,20,30);
is($one, 3, 'scalar, length');
is($two, undef, 'nothing else');
# shouldn't 'defined-or' be equivalent to a ternary with a check against undef?
# ($one, $two, $three) = defined #emptyness ? #emptyness : (10,20,30); # fails!
# "Can't use 'defined(#array)' (Maybe you should just omit the defined()?)"
# Probably #array // ... should fail in the same way, but instead it returns #array
# in a scalar context.
# so maybe this is a bug
};
done_testing();
Or can anybody give me a reasonable explanation for this behavior?
The behavior you are observing is the intended one. This is documented in perlop, in the section Logical Defined-Or:
EXPR1 // EXPR2 returns the value of EXPR1 if it's defined, otherwise, the value of EXPR2 is returned. (EXPR1 is evaluated in scalar context, EXPR2 in the context of // itself).
And, perldoc later provides the following example:
In particular, this means that you shouldn't use this for selecting between two aggregates for assignment:
#a = #b || #c; # This doesn't do the right thing
#a = scalar(#b) || #c; # because it really means this.
#a = #b ? #b : #c; # This works fine, though.
// must evaluate its left-hand side operator in scalar context since it requires a scalar to evaluate for defined-ness.
#a returns the number of elements the array contains in scalar context.
So #a // ... always returns the number of elements in #a (since all numbers are defined values).
The concepts of defined-ness or truth-ness aren't defined for a sequence of scalars ("list") as a whole. They only apply to individual scalars. As such, //, &&, and, ||, or, !, not and ?: require a scalar from their left-most operand, so they evaluate it in scalar context. xor needs to test the truth of both of its operands, and thus evaluates both in scalar context.
$ perl -M5.010 -e'
sub cx { print wantarray ? " list " : " scalar"; $_[0] }
print "// "; #a = cx($u) // cx(); say "";
print "&& "; #a = cx(0) && cx(); say "";
print "and"; #a = ( cx(1) and cx() ); say "";
print "|| "; #a = cx(0) || cx(); say "";
print "or "; #a = ( cx(0) or cx() ); say "";
print "xor"; #a = ( cx(0) xor cx(0) ); say "";
print "! "; #a = ! cx(); say "";
print "not"; #a = not cx(); say "";
print "?: "; #a = cx() ? 0 : 0;
#a = 1 ? cx() : 0;
#a = 0 ? 0 : cx(); say "";
'
// scalar list
&& scalar
and scalar list
|| scalar list
or scalar list
xor scalar scalar
! scalar
not scalar
?: scalar list list
You might be under the incorrect impression that #a always returns a list of its elements, and that this gets coerced into a count when evaluated in scalar context. But that's not the case.
There's simply no such thing as a list. When we say "evaluates to a list" or "returns a list", we simply mean "adds zero or more scalar to the stack". There's absolutely no difference between return a scalar and returning "a list of one scalar". Both refer to adding a scalar to the stack.
Since there's no list data structure being returned, there's nothing that can be magically coerced to a scalar in scalar context; its up to every operator to return a single scalar when evaluated in scalar context. This permits each operator to choose what they want to return in scalar context. It varies greatly.
In short, #a returns the number of elements in scalar context, not the elements it contains like it does in list context.
+-------------------------- (Scalar context) Returns 3
| +------------- (List context) Returns three scalars
| |
vvvv vvvvvvvv
() = #row // (10,20,30);
+-------------------------- (Scalar context) Returns 3
| +------------------- (List context) Returns three scalars
| | +------- (List context) Returns three scalars
| | |
vvvv vvvv vvvvvvvv
() = #row ? #row : (10,20,30);
Finally, let's analyze #row // ....
We've already established that #row is evaluated in scalar context in the above, and that it returns the number of elements in the array in array when it does.
Well, numerical values are necessarily not undef, so they are all defined. So that means that the right-hand size of #row // ... will never get evaluated. You might as well have written scalar(#row).
defined(#array) is a bit of a weird construct and Perl is trying to get rid of it. From perldoc -f defined:
Use of "defined" on aggregates (hashes and arrays) is no longer supported. It used to report whether memory for that aggregate had ever been allocated.
That's not testing if it currently has any elements! To check for size, simply use the array variable in scalar context (such as a conditional):
if( #array ) { ... }
And, Dada has already explained what the defined-or operator does, which adds its own twist to it.
// and || first impose scalar context on their left side argument. // checks whether that argumend is defined. || checks whether that argument is "not false". false in Perl is any of the values undef, 0, "0", or "".
The scalar value of an array is always defined so you can't use that in a check the way you did. #row // (10,20,30) is the same as defined(scalar(#row)) or (10,20,30).
For a longer discussion of context, see the documentation for the Want module.

Check specific value not in array

I have an array with two values and need to perform some operations if input is not in that array.
I tried like
if ($a ne ('value1' || 'value2')
if (($a ne 'value1' ) || ($a ne 'value2' ))
Both methods didn't work. Can anyone please help?
You could use the none function from List::MoreUtils.
If you really have an array as your subject line says then your code would look like this
use List::MoreUtils 'none';
if ( none { $_ eq $a } #array ) {
# Do stuff
}
or if you really have two constants then you could use this
if ( none { $_ eq $a } 'value1', 'value2' ) {
# Do stuff
}
but in this case I would prefer to see just
if ( $a ne 'value1' and $a ne 'value2' ) {
# Do stuff
}
$a is not in the array if it's different to the first element and it's different to the second one, too.
if ($x ne 'value1' and $x ne 'value2') {
For a real array of any size:
if (not grep $_ eq $x, #array) {
(I use $x instead of $a, as $a is special - see perlvar.)
if ($a ne ('value1' || 'value2')
evaluates to
if ($a ne 'value1')
and
if (($a ne 'value1' ) || ($a ne 'value2' ))
is always TRUE.
You might try
if ($a ne 'value1' and $a ne 'value2')
or
if (!grep{$a eq $_} 'value1', 'value2')
Building on the smartmatch solution by #Dilbertino (nice nick) using match::simple by #tobyink to ease the pain of smartmatch going away (I miss it already):
use match::simple;
my #array = qw(abcd.txt abcdeff.txt abcdweff.txt abcdefrgt.txt);
my $x="abcd.txt" ;
say "it's there" if ($x |M| \#array );
The |M| operator from match::simple can be replaced with a match function which speeds things up a bit (it is implemented with XS):
use match::simple qw(match);
my #array = qw(abcd.txt abcdeff.txt abcdweff.txt abcdefrgt.txt);
my $x="xyz.txt" ;
if ( match ( $x, \#array ) ) {
say "it's there!" ;
}
else {
say "no hay nada";
}
It's "simple" because the RHS controls the behavior. With match::simple if you are matching against an array on the RHS it should be an arrayref.
Smart::Match also has a none function. To use it you would do:
if ( $x ~~ none (#array) ) {
say "not here so do stuff ...";
}
Appendix
Discussion here on Stackoverlfow (see: Perl 5.20 and the fate of smart matching and given-when?) and elsewhere (c.f. the Perlmonks article by #ikegami from circa perl-5.18) gives the context for the smartmatch experiment. TLDR; things might change in the future but meanwhile, you can go back in time and use match::smart qw(match); with perl-5.8.9 proving once again that perl never dies; it just returns to its ecosystem.
In the future something like Smart::Match (i.e. the non-core CPAN module not the concept) can help supercharge a simplified smart matching operator with helper functions that read like adverbs and adjectives and have the added bonus (as I understand it) of clarifying/simplifying things for perl itself since the ~~ operator will have a less ambiguous context for its operations.
I would do something like this using grep with a regex match
#!/usr/bin/perl
use warnings;
use strict;
my #array = ('value1','value2');
if(grep(/\bvalue1\b|\bvalue2\b/, #array)){
print "Not Found\n";
}
else {
print "do something\n";
}
You can also use the smart match operator:
unless( $x ~~ ['value1','value2'] )
Your variable $a is not evaluated as a array without [INDEX] index, but is been treated as a scalar.
Two value array:
$array[0] = "X";
$array[1] = "Y";
or
#array = qw/X Y/;
Condition check using if:
if ( $array[0] ne "Your-String" || $array[1] ne "Your-String")

Why am I getting no output from this short Perl script?

Why isn't the below code returning any output? I am expecting it to print out "Contains".
sub is_member {
my ($x, #list) = #_;
foreach (#list) {
if ($x eq $_) {"contains"} else {"doesn't contain"}
}
}
my #a = qw(apple x orange but so nos how dod to it a b c);
print is_member("apple",#a)."\n";
Like below code just run fine, outputting "is palindrome"
sub is_palindrome {
my ($x) = #_;
if ($x eq reverse($x)){"is palindrome"} else {"Not a palindrome"}
}
print is_palindrome("radar")."\n";
This code:
if ($x eq $_) {"contains"} else {"doesn't contain"}
does not print or return anything. It evaluates two constants, but that's all. I'm surprised there isn't a complaint about missing semicolons, too. And the indentation is eccentric.
You probably want something more like:
sub is_member
{
my ($x, #list) = #_;
foreach (#list)
{
return "contains" if ($x eq $_);
}
return "doesn't contain";
}
for loops do not have return values. In is_palindrome, the if statement is evaluated by itself which produces the return value for the subroutine implicitly.
In the case of the for loop, even if the last statement evaluated inside a for loop became the return value, the last comparison made, "apple" eq "c", would be false.
If you want to do the test using a for loop, you will need to exit the loop early. But, in Perl, grep is the built-in way to test if the elements of a list satisfy a condition.
my $result = (grep $_ eq $x, #list) ? "contains" : "does not contain";
print "'#list' $result $x\n";
If you are only interested in the existence of a certain element, List::MoreUtils::any
and List::MoreUtils::first_index provide performance advantages in case the list is long.
The conditional operator, $cond ? $t : $f, is more useful for writing compact conditionals than trying to fit an if statement on a single line with braces and all.
to clarify on the return values of subs, by default, Perl returns the value of the evaluation of the last expression in the sub... unless it's in a loop. from perldoc:
If no return is found and if the last statement is an expression, its
value is returned. If the last statement is a loop control structure
like a foreach or a while , the returned value is unspecified. The
empty sub returns the empty list.
but as others have stated, you should always use return if you are returning anything, for both readability and stability.
it's also true that your sub is unnecessary. grep will return 0 or 1 in a scalar context (that you can use as boolean), or a new array of matching values in an array context; ex:
my #a = qw(apple x orange but so nos how dod to it a b c);
print "found" if grep /^orange$/, #a; # prints "found"
my #b = grep length > 3, #a;
print "#b" # prints "apple orange"

Perl logical and with multiple tests

Is it normal to write in such way:
if(($x && $y && $z) eq "test"){
}
If I am interested in ($x eq "test") && ($y eq "test") && ($z eq "test")?
It wouldn't be normal because it doesn't even work
$x && $y returns either $x or $y depending on whether the value of $x is true or not.
That means that ($x && $y) && $z returns either $x, $y or $z depending on the values of $x and $y.
That means that only one of $x, $y or $z will be compared against 'test'.
For example, you'll get a false positive (returns true when it should return false) when you have $x='abc'; $y='def'; $z='test';.
If you wanted something shorter, then you'd have to use something like
use List::MoreUtils qw( all );
if ( all { $_ eq "test" } $x, $y, $z )
No.
The expression $x && $y && $z is equivalent to the expression
$x ? $x : $y ? $y : $z
and will be evaluated separately from the expression on the other side of the eq operator.
Writing if ($x eq 'test' && $y eq 'test' && $z eq 'test') ... as you do is as reasonably terse as you're going to get.
As an elaboration on ikegami's answer, I thought I would show the code for the all() subroutine, as it is rather simple, and gives a good demonstration of the logic behind the answer to the question. And also, as it happens, makes a good demonstration for how prototypes work.
sub all (&#) {
my $f = shift;
foreach ( #_ ) {
return NO unless $f->();
}
return YES;
}
The prototypes & and # refer to a code reference, and a list of arguments. YES and NO are constants for true and false defined as follows:
# Use pure scalar boolean return values for compatibility with XS
use constant YES => ! 0;
use constant NO => ! 1;
The basic gist of this subroutine is to take a code reference (an anonymous subroutine) and execute it once for each argument, using $_ as the loop variable. If any argument causes the code block to return a false value, the subroutine returns false and ends.
With this code and these prototypes we can use the all subroutine much like map, with a code block first:
all { $_ eq "foo" } "foo", "bar", "baz";
If we remove the prototypes (&#), we must pass the code reference as a standalone, as part of the list:
all sub { $_ eq "foo" }, "foo", "bar", "baz";
Note the addition of the sub keyword, and the comma after the code block.

How to use local * on reference arguments?

This question is related to the last point of Item 46 in Effective Perl Programming.
I tested out this function, which allows you to pass array references, but access them as local arrays:
use strict;
sub max_v_local {
local ( *a, *b ) = #_;
my $n = #a > #b ? #a : #b;
my #result;
for ( my $i = 0 ; $i < $n ; $i++ ) {
push #result, $a[$i] > $b[$i] ? $a[$i] : $b[$i];
}
#result;
}
But I got the following errors unless I don't use strict:
Variable "#a" is not imported
Variable "#b" is not imported
Global symbol "#a" requires explicit package name
Global symbol "#b" requires explicit package name
Is there a way to do this with strict?
Update
Some further background. The above subroutine was a refinement of what follows. The subroutine takes 2 arrayrefs, but using the arrayrefs in the subroutine can get messy. The above code will probably be faster and is more readable since it enables you to access the arrayrefs as local arrays.
sub max_v {
my ( $a, $b ) = #_;
my $n = #$a > #$b ? #$a : #$b; # no. of items
my #result;
for ( my $i = 0 ; $i < $n ; $i++ ) {
push #result, $$a[$i] > $$b[$i] ? $$a[$i] : $$b[$i];
}
#result;
}
I haven't paid much attention to globs prior to this, so I'm having a look at them now. Turns out that they're not as complicated as I thought.
Yes. Declare them with our:
use strict;
sub max_v_local {
local ( *x, *y ) = #_;
our (#x, #y);
my $n = #x > #y ? #x : #y;
my #result;
for ( my $i = 0 ; $i < $n ; $i++ ) {
push #result, $x[$i] > $y[$i] ? $x[$i] : $y[$i];
}
#result;
}
(It's generally not a good idea to use variables named a or b for anything except sort.)
As cjm mentions, you need to declare the variables with our (or use fully qualified names).
Now for a few tips. First off, assigning from #_ into a glob unchecked is a bit of a gamble. I would write the line like this:
our (#a, #b);
local (*a, *b) = map \#$_ => #_;
That way, you have ensured that the only things passed to your subroutine are actually array references. Perl will throw an error if the value is not an array reference. You can of course write a verbose check if you want a more detailed message:
ref eq 'ARRAY' or die "..." for #_;
our (#a, #b);
local (*a, *b) = #_;
You want to use the package variables #a and #b, so you want to use our. It's almost a per-variable no strict "vars";, and it's lexically scoped.
sub max_v_local {
local ( *a, *b ) = #_;
our ( #a, #b );
...
}
But there is a problem in your algorithm. You're comparing elements of the longer array to elements that don't exist. That will give warnings and give the wrong result for negative values. Fix:
sub max_v_local {
local ( *a, *b ) = #_;
our ( #a, #b );
my $n = #a < #b ? #a : #b;
return
( map { $a[$_] > $b[$_] ? $a[$_] : $b[$_] } 0..$n-1 ),
#a[ #b .. $#a ],
#b[ #a .. $#b ];
}
Also, it's odd to take references and return a list, though. You might want to return an array reference. (return [ ... ];)
Think it might be because you haven't explicitly declared your variable #a and #b