Perl - increment value within ternary operator - perl

I am simply trying to increment a value within the ternary operator's 'true' section when the test() subroutine returns true, but set it back to zero when the it returns false.
I don't understand why the following code doesn't work:
use warnings;
use strict;
my $int = 5;
test() ? $int += 1 : $int = 0;
print "$int\n"; # => prints "0"
sub test {
return 1; #return true
}

The answer is fairly simple: perl's ternary operator is assignable
In particular, your code really means this:
(test() ? $int += 1 : $int) = 0;
You may recall that the result of an assignment is the variable being assigned to; this means that the following happens:
test() evaluates to true
$int += 1 is evaluated, incrementing $int to 6
The result of the assignment, $int, is assigned the value 0
This code will work how you want:
test() ? ($int++) : ($int = 0);
Or this:
$int += test() ? 1 : -$int; #If you want to be cute

Related

Perl - use 0 if string is empty

When using arithmetic expressions in combination with an undefined or empty string, perl throws an error. Is there a clean way to use zero in case a string is empty?
This does not work:
$x = 1 + $emptyVar
In bash you could use something like this for instance to use zero if the variable $emptyVar is empty:
x=1+${emptyVar:-0}
I am looking for something similar as this
There are many ways to do this. e.g.:
$x = $emptyVar;
$x += 1;
or maybe:
$x = 1 + ($emptyVar // 0); # defined-or operator
or maybe:
{
no warnings 'uninitialized';
$x = 1 + $emptyVar;
}
Of these, I usually use the second one. If the level of perl I'm using doesn't have defined-or, then a simple or (||) works fine, too.

print result of comparison operators [duplicate]

I have tried:
$var = false;
$var = FALSE;
$var = False;
None of these work. I get the error message
Bareword "false" not allowed while "strict subs" is in use.
In Perl, the following evaluate to false in conditionals:
0
'0'
undef
'' # Empty scalar
() # Empty list
('')
The rest are true. There are no barewords for true or false.
Since 5.36, you can use true and false from the builtin module/namespace. These are special true and false values that can be identified using is_bool. This is an experimental feature at this time.
But while these could be said to return the true and false, they are are but a true or false value respectively. In fact, every scalar is either true or false.
The most complete, concise definition of a false value I've come across is:
Anything that stringifies to the empty string or the string 0 is false. Everything else is true.
Therefore, the following values are false:
false (5.36+)
The empty string
Numerical value zero
An undefined value
An object with an overloaded boolean operator that evaluates one of the above.
A magical variable that evaluates to one of the above on fetch.
Any other scalar is true.
Keep in mind that an empty list literal (()) evaluates to an undefined value in scalar context, so it evaluates to something false.
A note on "true zeroes"
While numbers that stringify to 0 are false, strings that numify to zero aren't necessarily. The only false strings are 0 and the empty string. Any other string, even if it numifies to zero, is true.
The following are strings that are true as a boolean and zero as a number:
Without a warning:
"0.0"
"0E0"
"00"
"+0"
"-0"
" 0"
"0\n"
".0"
"0."
"0 but true"
"\t00"
"\n0e1"
"+0.e-9"
With a warning:
Any string for which Scalar::Util::looks_like_number returns false. (e.g. "abc")
Perl doesn't have a native boolean type, but you can use comparison of integers or strings in order to get the same behavior. Alan's example is a nice way of doing that using comparison of integers. Here's an example
my $boolean = 0;
if ( $boolean ) {
print "$boolean evaluates to true\n";
} else {
print "$boolean evaluates to false\n";
}
One thing that I've done in some of my programs is added the same behavior using a constant:
#!/usr/bin/perl
use strict;
use warnings;
use constant false => 0;
use constant true => 1;
my $val1 = true;
my $val2 = false;
print $val1, " && ", $val2;
if ( $val1 && $val2 ) {
print " evaluates to true.\n";
} else {
print " evaluates to false.\n";
}
print $val1, " || ", $val2;
if ( $val1 || $val2 ) {
print " evaluates to true.\n";
} else {
print " evaluates to false.\n";
}
The lines marked in "use constant" define a constant named true that always evaluates to 1, and a constant named false that always evaluates by 0. Because of the way that constants are defined in Perl, the following lines of code fails as well:
true = 0;
true = false;
The error message should say something like "Can't modify constant in scalar assignment."
I saw that in one of the comments you asked about comparing strings. You should know that because Perl combines strings and numeric types in scalar variables, you have different syntax for comparing strings and numbers:
my $var1 = "5.0";
my $var2 = "5";
print "using operator eq\n";
if ( $var1 eq $var2 ) {
print "$var1 and $var2 are equal!\n";
} else {
print "$var1 and $var2 are not equal!\n";
}
print "using operator ==\n";
if ( $var1 == $var2 ) {
print "$var1 and $var2 are equal!\n";
} else {
print "$var1 and $var2 are not equal!\n";
}
The difference between these operators is a very common source of confusion in Perl.
I recommend use boolean;. You have to install the boolean module from cpan though.
My favourites have always been
use constant FALSE => 1==0;
use constant TRUE => not FALSE;
which is completely independent from the internal representation.
I came across a tutorial which have a well explaination about What values are true and false in Perl. It state that:
Following scalar values are considered false:
undef - the undefined value
0 the number 0, even if you write it as 000 or 0.0
'' the empty string.
'0' the string that contains a single 0 digit.
All other scalar values, including the following are true:
1 any non-0 number
' ' the string with a space in it
'00' two or more 0 characters in a string
"0\n" a 0 followed by a newline
'true'
'false' yes, even the string 'false' evaluates to true.
There is another good tutorial which explain about Perl true and false.
Beautiful explanation given by bobf for Boolean values : True or False? A Quick Reference Guide
Truth tests for different values
Result of the expression when $var is:
Expression | 1 | '0.0' | a string | 0 | empty str | undef
--------------------+--------+--------+----------+-------+-----------+-------
if( $var ) | true | true | true | false | false | false
if( defined $var ) | true | true | true | true | true | false
if( $var eq '' ) | false | false | false | false | true | true
if( $var == 0 ) | false | true | true | true | true | true
use the following file prefix, this will add to your perl script eTRUE and eFALSE, it will actually be REAL(!) true and false (just like java)
#!/usr/bin/perl
use strict;
use warnings;
use constant { #real true false, compatible with encode_json decode_json for later (we don't want field:false... will be field:0...)
eTRUE => bless( do{\(my $o = 1)}, 'JSON::PP::Boolean' ),
eFALSE => bless( do{\(my $o = 0)}, 'JSON::PP::Boolean' )
};
There are, actually, few reasons why you should use that.
My reason is that working with JSON, I've got 0 and 1 as values to keys, but this hack will make sure correct values are kept along your script.
Booleans in Raku (the programming language formerly known as Perl_6):
~$ raku
Welcome to 𝐑𝐚𝐤𝐮𝐝𝐨™ v2021.06.
Implementing the 𝐑𝐚𝐤𝐮™ programming language v6.d.
Built on MoarVM version 2021.06.
To exit type 'exit' or '^D'
> my $var = False;
False
> say $var;
False
> say $var.^name
Bool
> say $var.WHAT
(Bool)
> say ++$var
True
> say --$var
False
> say $var.Int
0
> say $var.Int + 1
1
> say ($var.Int + 1).Bool
True
> say $var.Int - 1
-1
> say ($var.Int - 1).Bool
True
> say $var.succ
True
> say $var.Int.succ
1
> say $var.pred
False
> say $var.Int.pred
-1
> say ++($var.Int); #ERROR
Cannot resolve caller prefix:<++>(Int:D); the following candidates
match the type but require mutable arguments:
(Mu:D $a is rw)
(Int:D $a is rw --> Int:D)
#<SNIP>
> say --($var.Int); #ERROR
Cannot resolve caller prefix:<-->(Int:D); the following candidates
match the type but require mutable arguments:
(Mu:D $a is rw)
(Int:D $a is rw --> Int:D)
#<SNIP>
> exit
https://docs.raku.org/type/Bool
https://docs.raku.org/language/syntax#index-entry-Boolean_(literals)

pass 3 value to sub : Too many arguments for

I have an input like this:
100 200 A_30:120,A_140:180,B_180:220
100 300 A_70:220,B_130:300,A_190:200,A_60:300
I want to count number of A or B in each line and also compare range of A or B in each line with the range in two first column and return the length of intersection. e.g. output for first line: A:2 A_length:40 B:1 B_length:20
while(<>){
chomp($_);
my #line = split("\t| ", $_);
my $col1 = $line[0];
my $col2 = $line[1];
my #col3 = split(",",$line[2]);
my $A=0;
my $B=0;
my $A_length=0;
my $B_length=0;
for my $i (0 .. #col3-1){
my $col3 = $col3[$i];
if ($col3 =~ /A/){
my $length=0;
$length = range ($col3,$col1,$col2);
$A_length = $A_length+$length;
$A++;
}
if ($col3 =~ /B/){
my $length=0;
$length = range ($col3,$col1,$col2);
$B_length = $B_length+$length;
$B++;
}
$i++;
}
print("#A: ",$A,"\t","length_A: ",$A_length,"\t","#B: ",$B,"\t","length_B: ",$B_length,"\n");}
sub range {
my ($col3, $col1, $col2) = ($_[0],$_[1],$_[2]);
my #sub = split(":|_", $col3);
my $sub_strt = $sub[1];
my $sub_end = $sub[2];
my $sub_length;
if (($col1 >= $sub_strt) && ($col2 >= $sub_end)){
$sub_length = ($sub_end) - ($col1);}
if (($col1 >= $sub_strt) && ($col2 >= $sub_end)){
$sub_length = ($col2) - ($col1);}
if(($col1 <= $sub_strt) && ($col2 >= $sub_end)){
$sub_length = ($sub_end) - ($sub_strt);}
if(($col1 <= $sub_strt) && ($col2 <= $sub_end)){
$sub_length = ($col2) - ($sub_strt);}
return $sub_length;
}
I FIXED IT :)
Perl already has a builtin length function, which only takes one argument. As perl is compiling your script and gets to your length function call, it doesn't know about the sub length { ... } that you have defined later in the script, so it complains that you are using the builtin length function incorrectly.
How to fix this? This is Perl, so there are many ways
name your function something else. Making a function with the same name as a Perl builtin function is usually a bad idea
Call your function with the & sigil: my $length = &length($col3,$col1,$col2); That will be enough of a hint to the compiler that your function call does not refer to the builtin function.
Qualify your function call with a package name, in this case main::length($col3,$col1,$col2) or just ::length($col3,$col1,$col2).
Note that even if Perl did know about the length function you defined (you could get Perl to know by moving the sub length { ... } definition to the top of the script, for example), the function call would still be ambiguous to the compiler, the compiler would emit a warning like
Ambiguous call resolved as CORE::length(), qualify as such or use & at ...
and your script would still fail to compile. Here CORE::length would mean that Perl is resolving the ambiguity in favor of the builtin function.

Meaning of the '+=' operator

Could someone help me to understand what the '+=' operator means in a particular situation. The script says:
$receipts{$weather} += $receipt;
$days{$weather}++;
Assuming $foo += $bar, the += operator does the following:
$foo = $foo + $bar;
That is, increments $foo by $bar. Assuming $foo++, the ++ operator does the following:
$foo = $foo + 1;
That is, increments the variable by one.
With all this said, these operators also have some hidden perl magic. For example, the += and ++ operator does not give an uninitialized warning where the corresponding statement would:
# $foo is undefined
$foo += 10; # no warning
$foo++; # no warning
$foo = $foo + 10 # Use of uninitialized value $foo in addition
The ++ operator also works on strings
my $foo = 'a';
$foo++;
print $foo; # prints 'b'
The ++ operator comes in two flavours, post increment and pre increment. The return value of the expression is either calculated before or after the incrementation:
$foo = 1;
print ++$foo; # prints 2
print $foo++; # prints 2, but $foo is now 3
It is adding the value of $receipt to the value of $receipts{$weather} and storing the result back into $receipts{$weather}. It is the equivalent of:
$receipts{$weather} = $receipts{$weather} + $receipt
However, it may be implemented more efficiently in some cases.
See perldoc perlop:
"=" is the ordinary assignment operator.
Assignment operators work as in C. That is,
$a += 2;
is equivalent to
$a = $a + 2;
Example:
this example : int i = 2; i=i+4; and this example int i = 2; i+=4 are the same;

How do I use boolean variables in Perl?

I have tried:
$var = false;
$var = FALSE;
$var = False;
None of these work. I get the error message
Bareword "false" not allowed while "strict subs" is in use.
In Perl, the following evaluate to false in conditionals:
0
'0'
undef
'' # Empty scalar
() # Empty list
('')
The rest are true. There are no barewords for true or false.
Since 5.36, you can use true and false from the builtin module/namespace. These are special true and false values that can be identified using is_bool. This is an experimental feature at this time.
But while these could be said to return the true and false, they are are but a true or false value respectively. In fact, every scalar is either true or false.
The most complete, concise definition of a false value I've come across is:
Anything that stringifies to the empty string or the string 0 is false. Everything else is true.
Therefore, the following values are false:
false (5.36+)
The empty string
Numerical value zero
An undefined value
An object with an overloaded boolean operator that evaluates one of the above.
A magical variable that evaluates to one of the above on fetch.
Any other scalar is true.
Keep in mind that an empty list literal (()) evaluates to an undefined value in scalar context, so it evaluates to something false.
A note on "true zeroes"
While numbers that stringify to 0 are false, strings that numify to zero aren't necessarily. The only false strings are 0 and the empty string. Any other string, even if it numifies to zero, is true.
The following are strings that are true as a boolean and zero as a number:
Without a warning:
"0.0"
"0E0"
"00"
"+0"
"-0"
" 0"
"0\n"
".0"
"0."
"0 but true"
"\t00"
"\n0e1"
"+0.e-9"
With a warning:
Any string for which Scalar::Util::looks_like_number returns false. (e.g. "abc")
Perl doesn't have a native boolean type, but you can use comparison of integers or strings in order to get the same behavior. Alan's example is a nice way of doing that using comparison of integers. Here's an example
my $boolean = 0;
if ( $boolean ) {
print "$boolean evaluates to true\n";
} else {
print "$boolean evaluates to false\n";
}
One thing that I've done in some of my programs is added the same behavior using a constant:
#!/usr/bin/perl
use strict;
use warnings;
use constant false => 0;
use constant true => 1;
my $val1 = true;
my $val2 = false;
print $val1, " && ", $val2;
if ( $val1 && $val2 ) {
print " evaluates to true.\n";
} else {
print " evaluates to false.\n";
}
print $val1, " || ", $val2;
if ( $val1 || $val2 ) {
print " evaluates to true.\n";
} else {
print " evaluates to false.\n";
}
The lines marked in "use constant" define a constant named true that always evaluates to 1, and a constant named false that always evaluates by 0. Because of the way that constants are defined in Perl, the following lines of code fails as well:
true = 0;
true = false;
The error message should say something like "Can't modify constant in scalar assignment."
I saw that in one of the comments you asked about comparing strings. You should know that because Perl combines strings and numeric types in scalar variables, you have different syntax for comparing strings and numbers:
my $var1 = "5.0";
my $var2 = "5";
print "using operator eq\n";
if ( $var1 eq $var2 ) {
print "$var1 and $var2 are equal!\n";
} else {
print "$var1 and $var2 are not equal!\n";
}
print "using operator ==\n";
if ( $var1 == $var2 ) {
print "$var1 and $var2 are equal!\n";
} else {
print "$var1 and $var2 are not equal!\n";
}
The difference between these operators is a very common source of confusion in Perl.
I recommend use boolean;. You have to install the boolean module from cpan though.
My favourites have always been
use constant FALSE => 1==0;
use constant TRUE => not FALSE;
which is completely independent from the internal representation.
I came across a tutorial which have a well explaination about What values are true and false in Perl. It state that:
Following scalar values are considered false:
undef - the undefined value
0 the number 0, even if you write it as 000 or 0.0
'' the empty string.
'0' the string that contains a single 0 digit.
All other scalar values, including the following are true:
1 any non-0 number
' ' the string with a space in it
'00' two or more 0 characters in a string
"0\n" a 0 followed by a newline
'true'
'false' yes, even the string 'false' evaluates to true.
There is another good tutorial which explain about Perl true and false.
Beautiful explanation given by bobf for Boolean values : True or False? A Quick Reference Guide
Truth tests for different values
Result of the expression when $var is:
Expression | 1 | '0.0' | a string | 0 | empty str | undef
--------------------+--------+--------+----------+-------+-----------+-------
if( $var ) | true | true | true | false | false | false
if( defined $var ) | true | true | true | true | true | false
if( $var eq '' ) | false | false | false | false | true | true
if( $var == 0 ) | false | true | true | true | true | true
use the following file prefix, this will add to your perl script eTRUE and eFALSE, it will actually be REAL(!) true and false (just like java)
#!/usr/bin/perl
use strict;
use warnings;
use constant { #real true false, compatible with encode_json decode_json for later (we don't want field:false... will be field:0...)
eTRUE => bless( do{\(my $o = 1)}, 'JSON::PP::Boolean' ),
eFALSE => bless( do{\(my $o = 0)}, 'JSON::PP::Boolean' )
};
There are, actually, few reasons why you should use that.
My reason is that working with JSON, I've got 0 and 1 as values to keys, but this hack will make sure correct values are kept along your script.
Booleans in Raku (the programming language formerly known as Perl_6):
~$ raku
Welcome to 𝐑𝐚𝐤𝐮𝐝𝐨™ v2021.06.
Implementing the 𝐑𝐚𝐤𝐮™ programming language v6.d.
Built on MoarVM version 2021.06.
To exit type 'exit' or '^D'
> my $var = False;
False
> say $var;
False
> say $var.^name
Bool
> say $var.WHAT
(Bool)
> say ++$var
True
> say --$var
False
> say $var.Int
0
> say $var.Int + 1
1
> say ($var.Int + 1).Bool
True
> say $var.Int - 1
-1
> say ($var.Int - 1).Bool
True
> say $var.succ
True
> say $var.Int.succ
1
> say $var.pred
False
> say $var.Int.pred
-1
> say ++($var.Int); #ERROR
Cannot resolve caller prefix:<++>(Int:D); the following candidates
match the type but require mutable arguments:
(Mu:D $a is rw)
(Int:D $a is rw --> Int:D)
#<SNIP>
> say --($var.Int); #ERROR
Cannot resolve caller prefix:<-->(Int:D); the following candidates
match the type but require mutable arguments:
(Mu:D $a is rw)
(Int:D $a is rw --> Int:D)
#<SNIP>
> exit
https://docs.raku.org/type/Bool
https://docs.raku.org/language/syntax#index-entry-Boolean_(literals)