The new null coalescing operator in PHP is surely a great feature, somewhat comparable to JavaScript's usage of || for getting default values.
I already read some documentations and articles about this feature, but some things are still not quite clear to me.
1. Can I use this operator with any number of operands? For example, would this be valid?
$a = $p1 ?? $p2;
$b = $r1 ?? $r2 ?? $r3 ?? $r4 ?? $r5;
2. What is about falsy values, which are not null?
$test = false ?? 0 ?? 'test'; - what will be $test now? If it doesn't work with falsy values other than null, how can we achieve, that it works like JavaScript's ||?
I created this which should answer you questions.
Anyhow
The operator can be chained and it will return the first element in the chain that is set and not null.
According to the documentation it will return the result of its first operand if it exists and is not NULL, or else its second operand. Hence, if the first operand is false, it will return false.
Related
I'm learning groovy to work on smartthings and found a relatively common command among the various examples and existing code (see below).
Reading the function of the && operator I would think the "&& cmd.previousMeterValue" is superfluous. Or is there some code shortcut I'm missing?
Thanks
John
if (cmd.previousMeterValue && cmd.previousMeterValue != cmd.meterValue) {
do something
}
Not knowing what type previousMeterValue has, this answer is somewhat generic.
Groovy follows common operator precedence, i.e. != is evaluated before &&.
To show it explicitly, the full expression is the same as:
(cmd.previousMeterValue) && (cmd.previousMeterValue != cmd.meterValue)
cmd.previousMeterValue is testing the value for the Groovy-Truth.
Depending on value type, the following might be applicable:
Non-null object references are coerced to true.
Non-zero numbers are true.
So if the value is null or 0, the expression is false.
If the first part of the expression evaluated to false, then the second part is skipped.
The logical && operator: if the left operand is false, it knows that the result will be false in any case, so it won’t evaluate the right operand. The right operand will be evaluated only if the left operand is true.
If the first part of the expression evaluated to true, then cmd.previousMeterValue != cmd.meterValue is evaluated, using the following rule:
In Groovy == translates to a.compareTo(b)==0, if they are Comparable, and a.equals(b) otherwise.
So if value is a number object, then it is evaluated as:
cmd.previousMeterValue.compareTo(cmd.meterValue) != 0
This means that BigDecimal values are compared by value, ignoring specific scale.
I am trying to get a class, which combines list, set and map in Kotlin. I wished to write isScalar function, which should return true if object contains only one element and wrote
import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap
import it.unimi.dsi.fastutil.objects.ReferenceArrayList
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet
class Args {
var list : ReferenceArrayList<M>? = null
var set : ReferenceOpenHashSet<M>? = null
var map : Reference2ReferenceOpenHashMap<M, M>? = null
fun isEmpty() : Boolean {
return list === null && set === null && map === null
}
fun isScalar() : Boolean {
if(list !== null && list.size == 1) {
return true
}
}
}
Unfortunately it gave me error in comparison
list !== null && list.size == 1
saying
Smart cast to 'ReferenceArrayList<M>' is impossible, because 'list' is a mutable property that could have been changed by this time
As far as I understood, this is related with multithreaded assumption. In Java I would make function synchronized if would expect multithreding. Also, I would be able to disregard this at all, if I am not writing thread-safe.
How should I write in Kotlin?
I saw this solution https://stackoverflow.com/a/44596284/258483 but it expects MT, which I don't want to. How to avoid smart casting if it can't do it?
UPDATE
The question is how to do this in the same "procedural" form. How not to use smart casting?
UPDATE 2
Summarizing, as far as I understood, it is not possible/reasonable to explicitly compare variable with null in Kotlin at all. Because once you compare it, next time yous hould compare it with null again implicitly with such operations like .? and you can't avoid this.
If you take advantage of the fact that null cannot equal 1 (or anything else, really), you can make this check very concise:
fun isScalar() : Boolean =
list?.size == 1
When a null-safe call to list.size returns null, we get false because 1 != null. Otherwise, a comparison of whatever value size returns is made, and that works as you would expect.
By using the null safe operator (?.) you are avoiding a smart cast entirely. Kotlin gives us smart casts to make code cleaner, and this is one of the ways it protects us from misuses of that feature. Kotlin isn't going to protect us from everything (division by zero, the example you use in comments, for example). Your code is getting caught up in a legitimate case of where smart casting can go wrong, so Kotlin jumps in to help.
However, if you are absolutely sure there are no other threads working, then yes, this check is "wrong". You wouldn't need the warning in that case. Judging by this thread on kotlinlang.org, you aren't the only one!
You can perform the null check, and if it succeeds, access a read-only copy of your variable with let:
fun isScalar() : Boolean {
return list?.let { it.size == 1 } ?: false
}
If list is null, the entire let expression will evaluate to null, and the right side of the Elvis operator (false) will be returned.
If list is not null, then the let function is called, and result of the it.size == 1 expression is returned - it refers to the object that let was called on (list in this case). Since it's used with a safe call, this it will have a non-nullable type and size can be called on it.
I had the same problem in the given lines
sliderView.setSliderAdapter(adapter!!)
sliderView.setIndicatorAnimation(IndicatorAnimationType.WORM)
Finally, error resolved by adding !!
sliderView!!.setSliderAdapter(adapter!!)
sliderView!!.setIndicatorAnimation(IndicatorAnimationType.WORM)
This question is a little preemptive, as php 7 is not even released yet. I'm curious how the spaceship operator will be handled in the context of ternary operators.
so if I have a pre-spaceship ternary expression such as:
$foo = 1;
$bar = 0;
echo 'foo is ' . ( ($foo > $bar) ? 'greater than' : ( ($foo < $bar ) ? 'less than' : 'equal to' ) ) . ' bar.';
what would be the equivalent ternary operator using a comparison operator? Are ternaries going to have some means of handling this scenario? I use ternary operators quite a lot and am curious if there is some way to streamline the code in various instances where a comparison operator would be relevant.
The spaceship operator, as you can see from the documentation of its RFC, was though mainly to be used when having to deal with orderings.
I don't think it could be of help in shortening the code that you posted, mainly beacuse the ternary operator expects a boolean value and the ternary operator returns a "true" value (1 and -1) in both cases when the the values are different. In other words, when you cast its return value to a boolean, the spaceship operator is equivalent to the != operator.
Anyway, you could experiment with it on 3v4l.org, like I did here
Here's a clever approach for using the spaceship operator <=> as a poor man's three-way "ternary", also using an arrow function and array destructuring.
<?php
$relation = fn($a, $b) => [
-1 => 'less than',
0 => 'the same as',
1 => 'greater than'
][$a <=> $b];
$bar = 2;
// loop $foo from 1 through 3
foreach (range(1,3) as $foo) {
echo "foo is " . $relation($foo, $bar) . " bar.\n";
}
?>
Output:
foo is less than bar.
foo is the same as bar.
foo is greater than bar.
But watch out: it's clever, and clever code always requires more mental horsepower to understand, which makes it less maintainable. So there's the warning.
Why does
if (x) {
f();
}
call f() if x is an empty string ""?
Shouldn't empty strings in D implicitly convert to bool false like they do in Python and when empty arrays does it (in D)?
Update: I fixed the question. I had incorrectly reversed the reasoning logic. Luckily, the bright D minds understood what I meant anyway ;)
Conditions and if statements and loops are cast to bool by the compiler. So,
if(x) {...}
becomes
if(cast(bool)x) {...}
and in the case of arrays, casting to bool is equivalent to testing whether its ptr property is not null. So, it becomes
if(x.ptr !is null) {...}
In the case of arrays, this is actually a really bad test, because null arrays are considered to be the same as empty arrays. So, in most cases, you don't care whether an array is null or not. An array is essentially a struct that looks like
struct Array(T)
{
T* ptr;
size_t length;
}
The == operator will check whether all of the elements referred to by ptr are equal, but if length is 0 for both arrays, it doesn't care what the value of ptr is. That means that "" and null are equal (as are [] and null). However, the is operator explicitly checks the ptr properties for equality, so "" and null won't be the same according to the is operator, and whether a particular array which is empty has a null ptr depends on how its value was set. So, the fact that an array is empty really says nothing about whether it's null or not. You have to check with the is operator to know for sure.
The result of all this is that it's generally bad practice to put an array (or string) directly in a condition like you're doing with
if(x) {...}
Rather, you should be clear about what you're checking. Do you care whether it's empty? In that case, you should check either
if(x.empty) {...}
or
if(x.length == 0} {...}
Or do you really care that it's null? In that case, use the is operator:
if(x is null) {...}
The behavior of arrays in conditions is consistent with the rest of the language (e.g. pointer and reference types are checked to see whether they're null or not), but unfortunately, in practice, such behavior for arrays is quite bug-prone. So, I'd advise that you just don't ever put an array by itself in the condition of an if statement or loop.
the default conversion of arrays looks at the .ptr, which means only the default initialized arrays (or explicitly set to null) evaluate to false
as an added effect string literals in D are \0 terminated which means ("")[0] == '\0' and as such ("").ptr can't be null (which would lead to a segfault)
IMO it should look at the length and you can use the ptr when you need to
It does when I try it...
void main() {
import std.stdio;
string s = "";
if(s)
writeln("true"); // triggered
}
If it was "string s = null;" (which is the default initialization), it doesn't, because the null converts to false, but "" is ok on my computer. Are you sure it isn't null?
BTW, if you want to test for (non-)emptiness, the way I prefer to do it is if(x.length) and if(x.length == 0). Those work consistently for both "" and null, then if you specifically want null, do if(x is null). It is just a little more clear, especially since "" and null are interchangeable in a lot of other contexts in D.
Is this well defined?
Streamreader ^reader = gcnew Streamreader("test.txt");
String ^line;
while ((line = reader->ReadLine()) != nullptr && line != "")
{
//do stuff
}
I believe that I read somewhere that it is not guaranteed that the assignment is executed before the 2nd conditional. It may be that I'm wrong or that this just applies for C.
Google did not help me with this, that is why I am asking here :)
With && and ||, it is guaranteed to evaluate the first condition (including the assignment) before evaluating the second condition.
With bitwise & and |, on the other hand, no such guarantees are made.
There is a related answer here with a number of good references: Is short-circuiting logical operators mandated? And evaluation order?
Short answer if you haven't overloaded && and || you'll get short-circuit evaluation, which goes from left to right. Take a look in the link.