Why does // have lower precedence than equality in perl? - perl

Why does // have lower precedence than == in (at least) perl 5.010?
For example, this
use 5.010;
my $may_be_undefined = 1;
my $is_equal_to_two = ($may_be_undefined//0 == 2);
say $is_equal_to_two;
prints (for me) very unexpected result.

It's because of the category of operators which // falls under, aswell as ==.
== is an "equality operator" though // falls under the category of "C-style logical operators".
As an example; && is in the same "category" as //, with that said both of the statements below are equivalent when it comes to operator precedence. That might make it easier to understand?
print "hello world" if $may_be_undefined && 0 == 2;
print "hello world" if $may_be_undefined // 0 == 2;
Documentation of C-style Logical Defined-Or ( // )
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) .
The ||, // and && operators return the last value evaluated (unlike C's || and &&, which return 0 or 1).
Documentation of Operator Precedence and Associativity

Related

Change meaning of the operator "+" in perl

Currently "+" in perl means addition, in my project, we do string concatenation a lot. I know we can concatention with "." operator, like:
$x = $a . $b; #will concatenate string $a, and string $b
But "+" feels better. Wonder if there is a magic to make the following do concatenation.
$x = $a + $b;
Even better, make the it check the operator type, if both variables ($a, $b) are numbers, then do "addition" in the usual sense, otherwise, do concatenation.
I know in C++, one can overload the operator. Hope there is something similar in perl.
Thanks.
Yes, Perl too offers operator overloading.
package UnintuitiveString;
use Scalar::Util qw/looks_like_number/;
use overload '+' => \&concat,
'.' => \&concat,
'""' => \&as_string;
# Additionally, the following operators *have* to be overridden
# I suggest you raise an exception if an implementation does not make sense
# - * / % ** << >> x
# <=> cmp
# & | ^ ~
# atan2 cos sin exp log sqrt int
# 0+ bool
# ~~
sub new {
my ($class, $val) = #_;
return bless \$val => $class;
}
sub concat {
my ($self, $other, $swap) = #_;
# check for append mode
if (not defined $swap) {
$$self .= "$other";
return $self;
}
($self, $other) = ($other, $self) if $swap;
return UnintuitiveString->new("$self" . "$other");
}
sub as_string {
my ($self) = #_;
return $$self;
}
sub as_number {
my ($self) = #_;
return 0+$$self if looks_like_number $$self;
return undef;
}
Now we can do weird stuff like:
my $foo = UnintuitiveString->new(4);
my $bar = UnintuitiveString->new(2);
print $foo + $bar, "\n"; # "42"
my ($num_x, $num_y) = map { $_->as_number } $foo, $bar;
print $num_x + $num_y, "\n"; # "6"
$foo += 6;
print $foo + "\n"; # "46"
But just because we can do such things does not at all mean that we should:
Perl already has a concatenation operator: .. It's perfectly fine to use that.
Operator overloading comes at a massive performance cost. What previously was a single opcode in perl's VM is now a series of method calls and intermediate copies.
Changing the meaning of your operators is extremely confusing for people who actually know Perl. I stumbled a few times with the test cases above, when I was surprised that $foo + 6 wouldn't produce 10.
Perl's scalars are not a number or a string, they are both at the same time and are interpreted as one or the other depending on their usage context. This is actually half-true, and the scalars have different representations. They could be a string (PV), an integer (IV), a float (NV). However, once a PV is used in a numerical context like addition, a numerical value is determined and saved alongside the string, and we get an PVIV or PVNV. The reverse is also true: when a number is used in a stringy context, the formatted string is saved alongside the number. The looks_like_number function mentioned above determines whether a given string could represent a valid number like "42" or "NaN". Because just using a scalar in some context can change the representation, checking that a given scalar is a PV does not guarantee that it was intended to be a string, and an IV does not guarantee that it was intended to be an integer.
Perl has two sets of operators for a very good reason: If the “type” of a scalar is fluid, we need another way to explicitly request certain behavior. E.g. Perl has numeric comparison operators < <= == != >= > <=> and stringy comparison operators lt le eq ne ge gt cmp which can behave very differently: 4 XXX 12 will be -1 for <=> (because 4 is numerically smaller than 12), but 1 for cmp (because 4 comes later than 1 in most collation orders).
Other languages suffer a lot from having operators coerce their operands to required types but not offering two sets of operators. E.g. in Java, + is overloaded to concat strings. However, this leads to a loss of commutativity and associativity. Given three values x, y, z which can be either strings or numbers, we get different results for:
x + y and y + x – string concatenation is not commutative, whereas numeric addition is.
(x + y) + z and x + (y + z) – the + is not associative as soon as one string enters the playing field. Consider x = 1, y = 2, z = "4". Then the first evaluation order leads to "34", whereas the second leads to "124".
In Java, this is not a problem, because the language is statically typed, and because there are very few coercions (autoboxing, autounboxing, widening conversions, and stringification in concatenation). However, JavaScript (which is dynamically typed and will perform conversions from strings to numbers for other operators) shows the exact same behavior. Oops.
Stop this madness. Now. Perl's set of operators (barring smartmatch) is one of the best designed parts of the language (and its type system one of the worst parts from a modern viewpoint). If you dislike Perl because its operators make sense, you are free to use PHP instead (which, by the way, also uses . for concatenation to avoid such issues) :P

What does // and //= do in Perl?

I am new to Perl. I am still trying to learn the syntax of it. I have seen someone using // and //= in Perl but I couldn't find any resources on the web that explain this.
Can someone explain to me what exactly does it mean in layman terms? And what it actually does?
As kjprice mentioned, // is the logical 'defined or' operator and is documented here on the perlop page and the relevant excerpt is
it's exactly the same as ||, except that it tests the left hand side's definedness instead of its truth. Thus, EXPR1 // EXPR2 returns the value of EXPR1 if it's defined, otherwise, the value of EXPR2 is returned.
You can think of
my $var = EXPR1 // EXPR2;
as a short hand way of writing:
my $var;
if ( defined EXPR1 ) {
$var = EXPR1;
} else {
$var = EXPR2;
}
I often use this to either assign a default value to a variable unless a supplied by command line or config file value is supplied. Something like:
my $var = $config_version // 'foo';
The //= is a variation of this with an assignemnt mixed in. That same perlop page says this:
Modifying an assignment is equivalent to doing the assignment and then
modifying the variable that was assigned to.
For //= that means instead of writing something like
my $var = EXPR1 // EXPR2;
You could write
my $var = EXPR1;
$var //= EXPR2;
and get equivalent values.
From the perldoc perlop:
Logical Defined-Or
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, 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). Usually, this is the same result as defined(EXPR1) ? EXPR1 : EXPR2 (except that the ternary-operator form can be used as a lvalue, while EXPR1 // EXPR2cannot). 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).
So:
$NODEFINED // $DEFINED # will return the value of defined
$DEFINED1 // $DEFINED2 # will return the value of $DEFINED1
$a //= $b;
is shorthand for:
$a = $a // $b;
So $a will be set to the value $b ONLY if $a is undefined.
The $a //= 42; form is useful for setting a default for a variable that may not yet be defined.

Meaning of // operator in perl

I am new to perl. Can anyone please explain the meaning of // operator in perl.
It's the definedness operator. The expression:
A // B
will return A if it's defined, otherwise B.
It's very useful for getting default values if the source of the information is not defined, with things like:
$actualBalance = $balanceFromBank // 0;
or:
$confirmation = $userInput // "N";
See the relevant part of the perlop page for more detail and make a link of perlop for future reference, since Google searches and the punctuational Perl code don't mix that well :-)
The // operator is a logical defined-or. Perlop says:
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, 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).
Usually, this is the same result as defined(EXPR1) ? EXPR1 : EXPR2
(except that the ternary-operator form can be used as a lvalue, while
EXPR1 // EXPR2 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) .
In short: It returns the left side if that expression is defined (as in not undef), or the right side.
my $foo = undef;
say $foo // 42;
# 42
my $bar = 'bar';
say $bar // 42;
# bar
It's so called defined-or operator, which has been implemented in Perl 5.10. Example from the doc:
The following expression:
$a // $b
... is merely equivalent to
defined $a ? $a : $b
And the statement:
$c //= $d;
... can now be used instead of
$c = $d unless defined $c;
Here's how || and // are different:
use 5.010;
my $rabbits = 0;
say $rabbits || 1; # 1, as 0 || 1 evaluates to 1
say $rabbits // 1; # 0, as 0 is not `undef`
That is "defined-or". $abc // "default" is equivalent to defined($abc) ? $abc : "default". Meaning if the left side of // has a defined value then that value is used, otherwise the right side of it.
See "Logical defined-or" in the perlop man page.
is defined or
like,
my $a //= 3;
will assign 3 to $a
it is different from ||, which is simply, or in that:
my $a = "";
$a //= 3;
print "|$a|\n";
$a = "";
$a ||=5;
print "|$a|\n";
will print only |5|, because in the first case $a is defined (with a false value), while in the second it matters if $a evaluates to true or not.

What is the result of Perl's &&?

When I try this:
$a = 1;
$b = 2;
print ($a && $b) . "\n";
The result is 2. Why?
Quote perlop:
The "||", "//" and "&&" operators
return the last value evaluated
(unlike C's "||" and "&&", which
return 0 or 1).
The resulting 2 is considered true by Perl, so that when you use the && operator in a logical condition, everything works as expected. The added bonus is that you can use the logical operators in other contexts as well:
sub say_something {
say shift || 'default';
}
say_something('foo'); # prints 'foo'
say_something(); # prints 'default'
Or even as flow modifiers:
my $param = shift || die "Need param!";
-f $file && say "File exists.";
In the last two examples it’s good to realize that they could not work if the && and || operators did not short-circuit. If you shift a true value in on first line, there is no point evaluating the right side (die…), since the whole expression is true anyway. And if the file test fails on the second line, you don’t need to evaluate the right side again, since the overall result is false. If the logical operators insisted on evaluating the whole expression anyway, we could not use them this way.
That's how the && operator works: if the left-hand argument evaluates as true, the value of the expression is that of the value of the right-hand argument. This is covered on the perlop page.
However, you've also let yourself open to a much more subtle problem. You'll find that the newline doesn't get printed. This is because if you put an expression in brackets after print (or any other function name) the arguments passed to print are just those in the brackets. To get notice of this, make sure you switch on warnings. Put these lines at the top of each program:
#!/usr/bin/perl -w
use strict;
until you understand them enough to decide for yourself whether to continue with them. :-)
In your case, you'll get this:
print (...) interpreted as function at p line 7.
Useless use of concatenation (.) or string in void context at p line 7.
Because the && operator evaluates the right operand and returns the result when the left operand evaluates to true.

How do I compare two strings in Perl?

How do I compare two strings in Perl?
I am learning Perl, I had this basic question looked it up here on StackOverflow and found no good answer so I thought I would ask.
See perldoc perlop. Use lt, gt, eq, ne, and cmp as appropriate for string comparisons:
Binary eq returns true if the left argument is stringwise equal to the right argument.
Binary ne returns true if the left argument is stringwise not equal to the right argument.
Binary cmp returns -1, 0, or 1 depending on whether the left argument is stringwise less than, equal to, or greater than the right argument.
Binary ~~ does a smartmatch between its arguments. ...
lt, le, ge, gt and cmp use the collation (sort) order specified by the current locale if a legacy use locale (but not use locale ':not_characters') is in effect. See perllocale. Do not mix these with Unicode, only with legacy binary encodings. The standard Unicode::Collate and Unicode::Collate::Locale modules offer much more powerful solutions to collation issues.
cmp Compare
'a' cmp 'b' # -1
'b' cmp 'a' # 1
'a' cmp 'a' # 0
eq Equal to
'a' eq 'b' # 0
'b' eq 'a' # 0
'a' eq 'a' # 1
ne Not-Equal to
'a' ne 'b' # 1
'b' ne 'a' # 1
'a' ne 'a' # 0
lt Less than
'a' lt 'b' # 1
'b' lt 'a' # 0
'a' lt 'a' # 0
le Less than or equal to
'a' le 'b' # 1
'b' le 'a' # 0
'a' le 'a' # 1
gt Greater than
'a' gt 'b' # 0
'b' gt 'a' # 1
'a' gt 'a' # 0
ge Greater than or equal to
'a' ge 'b' # 0
'b' ge 'a' # 1
'a' ge 'a' # 1
See perldoc perlop for more information.
( I'm simplifying this a little bit as all but cmp return a value that is both an empty string, and a numerically zero value instead of 0, and a value that is both the string '1' and the numeric value 1. These are the same values you will always get from boolean operators in Perl. You should really only be using the return values for boolean or numeric operations, in which case the difference doesn't really matter. )
In addtion to Sinan Ünür comprehensive listing of string comparison operators, Perl 5.10 adds the smart match operator.
The smart match operator compares two items based on their type. See the chart below for the 5.10 behavior (I believe this behavior is changing slightly in 5.10.1):
perldoc perlsyn "Smart matching in detail":
The behaviour of a smart match depends on what type of thing its arguments are. It is always commutative, i.e. $a ~~ $b behaves the same as $b ~~ $a . The behaviour is determined by the following table: the first row that applies, in either order, determines the match behaviour.
$a $b Type of Match Implied Matching Code
====== ===== ===================== =============
(overloading trumps everything)
Code[+] Code[+] referential equality $a == $b
Any Code[+] scalar sub truth $b−>($a)
Hash Hash hash keys identical [sort keys %$a]~~[sort keys %$b]
Hash Array hash slice existence grep {exists $a−>{$_}} #$b
Hash Regex hash key grep grep /$b/, keys %$a
Hash Any hash entry existence exists $a−>{$b}
Array Array arrays are identical[*]
Array Regex array grep grep /$b/, #$a
Array Num array contains number grep $_ == $b, #$a
Array Any array contains string grep $_ eq $b, #$a
Any undef undefined !defined $a
Any Regex pattern match $a =~ /$b/
Code() Code() results are equal $a−>() eq $b−>()
Any Code() simple closure truth $b−>() # ignoring $a
Num numish[!] numeric equality $a == $b
Any Str string equality $a eq $b
Any Num numeric equality $a == $b
Any Any string equality $a eq $b
+ − this must be a code reference whose prototype (if present) is not ""
(subs with a "" prototype are dealt with by the 'Code()' entry lower down)
* − that is, each element matches the element of same index in the other
array. If a circular reference is found, we fall back to referential
equality.
! − either a real number, or a string that looks like a number
The "matching code" doesn't represent the real matching code, of course: it's just there to explain the intended meaning. Unlike grep, the smart match operator will short-circuit whenever it can.
Custom matching via overloading
You can change the way that an object is matched by overloading the ~~ operator. This trumps the usual smart match semantics. See overload.
The obvious subtext of this question is:
why can't you just use == to check if two strings are the same?
Perl doesn't have distinct data types for text vs. numbers. They are both represented by the type "scalar". Put another way, strings are numbers if you use them as such.
if ( 4 == "4" ) { print "true"; } else { print "false"; }
true
if ( "4" == "4.0" ) { print "true"; } else { print "false"; }
true
print "3"+4
7
Since text and numbers aren't differentiated by the language, we can't simply overload the == operator to do the right thing for both cases. Therefore, Perl provides eq to compare values as text:
if ( "4" eq "4.0" ) { print "true"; } else { print "false"; }
false
if ( "4.0" eq "4.0" ) { print "true"; } else { print "false"; }
true
In short:
Perl doesn't have a data-type exclusively for text strings
use == or !=, to compare two operands as numbers
use eq or ne, to compare two operands as text
There are many other functions and operators that can be used to compare scalar values, but knowing the distinction between these two forms is an important first step.
print "Matched!\n" if ($str1 eq $str2)
Perl has seperate string comparison and numeric comparison operators to help with the loose typing in the language. You should read perlop for all the different operators.
And if you'd like to extract the differences between the two strings, you can use String::Diff.
I came looking for a solution where in perl I could compare if A > B or Z < AA. Nothing here worked reliably for me so I came up with my own solution. The tricks is to assign a number for each letter
For example
A=1
B=2
C=3 and so on
Then when time comes to compare if A > B you get the corresponding numbers and compare them in this case 1 > 2
Heres working perl code.
# header
use warnings;
use strict;
#create a hash of letters
my %my_hash_lookup;
my $letter_counter=0;
foreach my $letters ('A'..'ZZ')
{
#print "$letters \n";
$letter_counter++;
my $key = $letters;
my $keyValue = $letter_counter;
$my_hash_lookup{$key}=$keyValue;
}
my $size = keys %my_hash_lookup;
print "hash size: $size ...\n";
#get number value of string letters
my $my_hash_value1 = $my_hash_lookup{"A"};
my $my_hash_value2 = $my_hash_lookup{"B"};
if ( (defined $my_hash_value1) && (defined $my_hash_value2))
{
if ($my_hash_value1 == $my_hash_value2)
{
#equal
}
elsif ($my_hash_value1 > $my_hash_value2)
{
#greater than
}
elsif ($my_hash_value1 < $my_hash_value2)
{
#less than
}
}