Priority in chained comparisons in Julia, does "var1 && var2 != 1" mean "(var1 and var2) != 1"? - comparison-operators

I have a questions regarding the chained comparisons in Julia. I read this section in the manual but it is still unclear.
In Julia, does this:
if var1 && var2 != 1
mean this (in Python):
if (var1 and var2) != 1:
Thank you!

You can always quote an expression to see how the parser interprets it:
julia> :(var1 && var2 != 1)
:(var1 && (var2!=1))
In this case, the != binds more tightly than the &&. This is standard precedence in languages that have these two operators) such as C and Java.

From what I could read on that page and a linked page (http://docs.julialang.org/en/latest/manual/control-flow/#man-short-circuit-evaluation), no. The order of operations is different. It ends up like this:
if (var1) && (var2 != 1)
First, the xscalar variable gets checked for a value that would satisfy an if statement, as if you did
if var1
Then, if, and only if that is accepted, does the next part get evaluated:
if var2 != 1
In other words, these two statements are roughly equivalent:
if var1
if var2 != 1
and
if var1 && var2 != 1
(forgive the lack of julia syntax knowledge)
A python equivalent of this would be:
if var1 and var2 != 1:
or, with parentheses to show with more clarity,
if (var1) and (var2 != 1) :

Related

In 'sh' how to put the result of a string comparison into a variable?

In basic 'shell', how do I put the result of a string comparison into a boolean variable?
Consider:
isweekday() {
w=$(date +%w)
if [[ $w == "0" ]] || [[ $w == "6" ]]; then
false
else
true
fi
}
One can debate whether it would be clearer or not, but is there a way to assign the result of the 'if' expression to a boolean variable, e.g.
isweekday() {
w=$(date +%w)
wd=<boolean result of [[ $w == "0" ]] || [[ $w == "6" ]]>
return $wd
}
After some experimentation, I got closer to what I want but it still isn't what I'm after:
isweekday() {
w=$(date +%w)
[[ $w == "0" ]] || [[ $w == "6" ]]
}
This works and does not require the conditional, but it looks wrong, however if you do:
if isweekday; then
echo 'weekday'
fi
you will get the right result. This seems to be because the exit code of 'true' is 0 and the exit code of 'false' is 1 (not quite sure why that is...)
There are no boolean variables. All shell variables are strings (though there are limited facilities for interpreting them as integer numbers for basic comparisons etc and basic arithmetic).
The exit code 0 is reserved for success; all other exit codes (up to the maximum 255) signify an error (though some nonstandard tools use this facility to communicate non-error results by way of convention; the caller is then assumed to understand and agree on this ad-hoc use of the exit code).
Perhaps then the simplest answer to what you appear to be asking is to save the exit code. It is exposed in the variable $?. But very often, you should not need to explicitly examine its value; indeed, your final isweekday code looks by far the most idiomatic and natural, and returns this code from [[ implicitly.
I don't understand why you think your final code "looks wrong"; this is precisely how you would use a function in a conditional.
However, in some sense, a case statement would look less cluttered here (but this syntax is somewhat jarring at first for other reasons, until you get used to it).
is_weekday () {
case $(date +%w) in
0 | 6) return 1;;
esac
return 0
}
This is portable to POSIX sh, unlike the Bash-only [[...]] syntax you were using. Perhaps see also Difference between sh and bash
The standard approach in Shell is to use the exit code of a command as the true/false value where zero indicates true and non-zero false. Also, I would instead define a function which tests if it's weekend today since that is the exception so to speak. It's also a good idea to define w as a local variable and to quote all variables which could in the general case contain a space or be undefined, something which can lead to a syntax error after variable expansion. Here is my suggestion:
IsWeekend()
{
local w="$(date +%w)"
[ "$w" = 0 ] || [ "$w" = 6 ]
}

Unexpected behaviours with Raku lambdas that are supposed to be equal (I guess)

I'm learning Raku as a passion project and I wanted to implement a simple fizzbuzz, why is join only retaining buzz if I write lambdas with pointy blocks?
my $iif =-> $x,$y,$z {if $x {$y} else {$z}}
my $modToString =-> $x,$y,$z {$iif($x%%$y,$z,'')}
my $FB =-> $x {join($modToString($x,3,'fizz'),$modToString($x,5,'buzz'))}
my $logic =-> $x {$iif($FB($x),$FB($x),$x)}
say map(-> $x {$logic($x)}, 1..100)
$modToString(1,3,'fizz')
>
$modToString(3,3,'fizz')
> fizz
$modToString(3,5,'buzz')
>
$modToString(5,5,'buzz')
> buzz
If I transform the pointy blocks variables into placeholder variables, Rakudo throws an error:
my $iif = {if $^x {$^y} else {$^z}};
my $modToString = {$iif($^x%%$^y,$^z,'')};
my $FB = {join($modToString($^x,3,'fizz'),$modToString($^x,5,'buzz'))}
my $logic = {$iif($FB($^x),$FB($^x),$^x)}
say map(-> $x {$logic($x)}, 1..100)
Too many positionals passed; expected 1 argument but got 3
in block at <unknown file> line 1
in block at <unknown file> line 1
in block at <unknown file> line 1
in block at <unknown file> line 1
in block <unit> at <unknown file> line 1
If I put the brackets around the join arguments it just outputs the numbers:
my $iif =-> $x,$y,$z {if $x {$y} else {$z}}
my $modToString =-> $x,$y,$z {$iif($x%%$y,$z,'')}
my $FB =-> $x {join(<$modToString($x,3,'fizz'),$modToString($x,5,'buzz')>)}
my $logic =-> $x {$iif($FB($x),$FB($x),$x)}
say map(-> $x {$logic($x)}, 1..100)
Why?
Because lots of things in Raku are blocks, even things that don't look like it. In particular, this includes the "argument" to control flow like if.
if 1 { 2 } else { 3 }
We've actually written two blocks here. One is a constant function returning 2 and the other is a constant function returning 3. Now, usually, this is transparent to us and the Raku engine is smart enough to compile those away. But they're still there. In fact, we can make them explicit. The following behaves identically to the above if statement.
if 1 -> { 2 } else -> { 3 }
In your case, however, it ends up mattering. Anonymous arguments (the ones with the ^ twigil) bind to the innermost block. So you've written
{if $^x {$^y} else {$^z}}
and you intended that it be equivalent to
-> $x, $y, $z {if $x {$y} else {$z}}
but what you actually wrote was
-> $x {if $x -> $y {$y} else -> $z {$z}};
So you've really written a function of one argument and passed it three arguments, as the error message states.
As a broad rule, you can generally assume that anytime you see a {, it either begins a hash literal or a block. And the latter always introduces a scope in which local variables and arguments can exist.
In your particular case, you can use the ternary ??!! operator (this is the same thing as ?: in most other languages like C++ or Java)
{$^x ?? $^y !! $^z}
This operator doesn't short-circuit and doesn't introduce blocks, so it'll work fine.
Migrating OP's solution from the question to an answer.
After Silvio Mayolo's answer I understood the problem and they also pointed out that I wrote a pointless ternary operator!
I also typed join instead of the tilde! I'm happy to say that my fizzbuzz now works:
my $modToString =-> $x,$y,$z {$x%%$y??$z!!''}
my $FB =-> $x {$modToString($x,3,'fizz')~$modToString($x,5,'buzz')}
my $logic =-> $x {$FB($x)??$FB($x)!!$x}
say map(-> $x {$logic($x)}, 1..100)

Shell Scripting Ternary operator to get string result

In shell scripting, I am using ternary operator like this:
(( numVar == numVal ? (resVar=1) : (resVar=0) ))
I watched shell scripting tutorial by Derek Banas and got the above syntax at 41:00 of the video
https://www.youtube.com/watch?v=hwrnmQumtPw&t=73s
The above code works when we assign numbers to resVar, but if I try to assign a string to resVar, it always returns 0.
(( numVar == numVal ? (resVar="Yop") : (resVar="Nop") ))
and also tried
resVar=$(( numVar == numVal ? (echo "Yop") : (echo "Nop") ))
So which is the right way to do this?
You didn't tell us what shell you use but it's possible you use
bash or something similar. Ternary operator in Bash works only with numbers as
explained in man bash under ARITHMETIC EVALUATION section:
The shell allows arithmetic expressions to be evaluated, under
certain circumstances (see the let and declare builtin commands and
Arithmetic Expansion). Evaluation is done in fixed-width integers
with no check for over- flow, though division by 0 is trapped and
flagged as an error. The operators and their precedence,
associativity, and values are the same as in the C language. The
following list of operators is grouped into levels of
equal-precedence operators. The levels are listed in order of
decreasing precedence.
(...)
expr?expr:expr
conditional operator
And the reason that resVar is assigned 0 when you use "Yop" or
"Nop" is because such string is not a valid number in bash and
therefore it's evaluated to 0. It's also explained in man bash in
the same paragraph:
A null value evaluates to 0.
It's also explained in this Wikipedia
article if you find it
easier to read:
A true ternary operator only exists for arithmetic expressions:
((result = condition ? value_if_true : value_if_false))
For strings there only exist workarounds, like e.g.:
result=$([ "$a" == "$b" ] && echo "value_if_true" || echo
"value_if_false")
(where "$a" == "$b" can be any condition test, respective [, can
evaluate.)
Arkadiusz already pointed out that ternary operators are an arithmetic feature in bash, not usable in strings. If you want this kind of functionality in strings, you can always use arrays:
$ arr=(Nop Yop)
$ declare -p arr
declare -a arr='([0]="Nop" [1]="Yop")'
$ numVar=5; numVal=5; resvar="${arr[$((numVar == numVal ? 1 : 0))]}"; echo "$resvar"
Yop
$ numVar=2; numVal=5; resvar="${arr[$((numVar == numVal ? 1 : 0))]}"; echo "$resvar"
Nop
Of course, if you're just dealing with two values that can be in position 0 and 1 in your array, you don't need the ternary; the following achieves the same thing:
$ resvar="${arr[$((numVar==numVal))]}"
you can use this simple expression :
resVar=$([ numVar == numVal ] && echo "Yop" || echo "Nop")
Running with Gohti's idea to make the script more readable:
#!/bin/bash
declare -a resp='([0]="not safe" [1]="safe")'
temp=70; ok=$(( $temp > 60 ? 1 : 0 ))
printf "The temperature is $temp Fahrenheit, it is ${resp[$ok]} to go outside\n";
temp=20; ok=$(( $temp > 60 ? 1 : 0 ))
printf "The temperature is $temp Fahrenheit, it is ${resp[$ok]} to go outside\n";

String compare in Perl with "eq" vs "==" [duplicate]

This question already has answers here:
How do I compare two strings in Perl?
(7 answers)
Closed 5 years ago.
I am (a complete Perl newbie) doing string compare in an if statement:
If I do following:
if ($str1 == "taste" && $str2 == "waste") { }
I see the correct result (i.e. if the condition matches, it evaluates the "then" block). But I see these warnings:
Argument "taste" isn't numeric in numeric eq (==) at line number x.
Argument "waste" isn't numeric in numeric eq (==) at line number x.
But if I do:
if ($str1 eq "taste" && $str2 eq "waste") { }
Even if the if condition is satisfied, it doesn't evaluate the "then" block.
Here, $str1 is taste and $str2 is waste.
How should I fix this?
First, eq is for comparing strings; == is for comparing numbers.
Even if the "if" condition is satisfied, it doesn't evaluate the "then" block.
I think your problem is that your variables don't contain what you think they do. I think your $str1 or $str2 contains something like "taste\n" or so. Check them by printing before your if: print "str1='$str1'\n";.
The trailing newline can be removed with the chomp($str1); function.
== does a numeric comparison: it converts both arguments to a number and then compares them. As long as $str1 and $str2 both evaluate to 0 as numbers, the condition will be satisfied.
eq does a string comparison: the two arguments must match lexically (case-sensitive) for the condition to be satisfied.
"foo" == "bar"; # True, both strings evaluate to 0.
"foo" eq "bar"; # False, the strings are not equivalent.
"Foo" eq "foo"; # False, the F characters are different cases.
"foo" eq "foo"; # True, both strings match exactly.
Did you try to chomp the $str1 and $str2?
I found a similar issue with using (another) $str1 eq 'Y' and it only went away when I first did:
chomp($str1);
if ($str1 eq 'Y') {
....
}
works after that.
Hope that helps.
Maybe the condition you are using is incorrect:
$str1 == "taste" && $str2 == "waste"
The program will enter into THEN part only when both of the stated conditions are true.
You can try with $str1 == "taste" || $str2 == "waste". This will execute the THEN part if anyone of the above conditions are true.

How to tell apart numeric scalars and string scalars in Perl?

Perl usually converts numeric to string values and vice versa transparently. Yet there must be something which allows e.g. Data::Dumper to discriminate between both, as in this example:
use Data::Dumper;
print Dumper('1', 1);
# output:
$VAR1 = '1';
$VAR2 = 1;
Is there a Perl function which allows me to discriminate in a similar way whether a scalar's value is stored as number or as string?
A scalar has a number of different fields. When using Perl 5.8 or higher, Data::Dumper inspects if there's anything in the IV (integer value) field. Specifically, it uses something similar to the following:
use B qw( svref_2object SVf_IOK );
sub create_data_dumper_literal {
my ($x) = #_; # This copying is important as it "resolves" magic.
return "undef" if !defined($x);
my $sv = svref_2object(\$x);
my $iok = $sv->FLAGS & SVf_IOK;
return "$x" if $iok;
$x =~ s/(['\\])/\\$1/g;
return "'$x'";
}
Checks:
Signed integer (IV): ($sv->FLAGS & SVf_IOK) && !($sv->FLAGS & SVf_IVisUV)
Unsigned integer (IV): ($sv->FLAGS & SVf_IOK) && ($sv->FLAGS & SVf_IVisUV)
Floating-point number (NV): $sv->FLAGS & SVf_NOK
Downgraded string (PV): ($sv->FLAGS & SVf_POK) && !($sv->FLAGS & SVf_UTF8)
Upgraded string (PV): ($sv->FLAGS & SVf_POK) && ($sv->FLAGS & SVf_UTF8)
You could use similar tricks. But keep in mind,
It'll be very hard to stringify floating point numbers without loss.
You need to properly escape certain bytes (e.g. NUL) in string literals.
A scalar can have more than one value stored in it. For example, !!0 contains a string (the empty string), a floating point number (0) and a signed integer (0). As you can see, the different values aren't even always equivalent. For a more dramatic example, check out the following:
$ perl -E'open($fh, "non-existent"); say for 0+$!, "".$!;'
2
No such file or directory
It is more complicated. Perl changes the internal representation of a variable depending on the context the variable is used in:
perl -MDevel::Peek -e '
$x = 1; print Dump $x;
$x eq "a"; print Dump $x;
$x .= q(); print Dump $x;
'
SV = IV(0x794c68) at 0x794c78
REFCNT = 1
FLAGS = (IOK,pIOK)
IV = 1
SV = PVIV(0x7800b8) at 0x794c78
REFCNT = 1
FLAGS = (IOK,POK,pIOK,pPOK)
IV = 1
PV = 0x785320 "1"\0
CUR = 1
LEN = 16
SV = PVIV(0x7800b8) at 0x794c78
REFCNT = 1
FLAGS = (POK,pPOK)
IV = 1
PV = 0x785320 "1"\0
CUR = 1
LEN = 16
There's no way to find this out using pure perl. Data::Dumper uses a C library to achieve it. If forced to use Perl it doesn't discriminate strings from numbers if they look like decimal numbers.
use Data::Dumper;
$Data::Dumper::Useperl = 1;
print Dumper(['1',1])."\n";
#output
$VAR1 = [
1,
1
];
Based on your comment that this is to determine whether quoting is needed for an SQL statement, I would say that the correct solution is to use placeholders, which are described in the DBI documentation.
As a rule, you should not interpolate variables directly in your query string.
One simple solution that wasn't mentioned was Scalar::Util's looks_like_number. Scalar::Util is a core module since 5.7.3 and looks_like_number uses the perlapi to determine if the scalar is numeric.
The autobox::universal module, which comes with autobox, provides a type function which can be used for this purpose:
use autobox::universal qw(type);
say type("42"); # STRING
say type(42); # INTEGER
say type(42.0); # FLOAT
say type(undef); # UNDEF
When a variable is used as a number, that causes the variable to be presumed numeric in subsequent contexts. However, the reverse isn't exactly true, as this example shows:
use Data::Dumper;
my $foo = '1';
print Dumper $foo; #character
my $bar = $foo + 0;
print Dumper $foo; #numeric
$bar = $foo . ' ';
print Dumper $foo; #still numeric!
$foo = $foo . '';
print Dumper $foo; #character
One might expect the third operation to put $foo back in a string context (reversing $foo + 0), but it does not.
If you want to check whether something is a number, the standard way is to use a regex. What you check for varies based on what kind of number you want:
if ($foo =~ /^\d+$/) { print "positive integer" }
if ($foo =~ /^-?\d+$/) { print "integer" }
if ($foo =~ /^\d+\.\d+$/) { print "Decimal" }
And so on.
It is not generally useful to check how something is stored internally--you typically don't need to worry about this. However, if you want to duplicate what Dumper is doing here, that's no problem:
if ((Dumper $foo) =~ /'/) {print "character";}
If the output of Dumper contains a single quote, that means it is showing a variable that is represented in string form.
You might want to try Params::Util::_NUMBER:
use Params::Util qw<_NUMBER>;
unless ( _NUMBER( $scalar ) or $scalar =~ /^'.*'$/ ) {
$scalar =~ s/'/''/g;
$scalar = "'$scalar'";
}
The following function returns true (1) if the input is numeric and false ("") if it is a string. The function also returns true (-1) if the input is a numeric Inf or NaN. Similar code can be found in the JSON::PP module.
sub is_numeric {
my $value = shift;
no warnings 'numeric';
# string & "" -> ""
# number & "" -> 0 (with warning)
# nan and inf can detect as numbers, so check with * 0
return unless length((my $dummy = "") & $value);
return unless 0 + $value eq $value;
return 1 if $value * 0 == 0; # finite number
return -1; # inf or nan
}
I don't think there is perl function to find type of value. One can find type of DS(scalar,array,hash). Can use regex to find type of value.

Resources