#NotNull on func arg warns arg == null is always false. But not really? - intellij-idea

Let's say I have a function with arguments annotated by Jetbrain's #NotNull, like so:
public static boolean birthdaysAreEqual(#NotNull clazz b1, #NotNull Birthday b2) {
if (b1 == null || b2 == null) {
// Custom handling here
throw new NullPointerException("birthdays cannot be null");
}
return b1.isEqualTo(b2);
}
My IDE (IntelliJ) will warn me that the condition is always 'false'`, and suggest to remove the check, implying it is redundant.
But I'm able to call this function with null inputs, in which case the if conditional is useful for catching the problem early on and handling it.
Is it then not good behavior for the IDE to label the if condition as redundant? Or am I missing something (maybe another annotation that triggers actual input validation?)?

Related

Proposed change of `equals` to `==` can't be applied to Char and String?

I have a function as below.
fun process(string: String?): Int {
if (string != null) {
return string.filter { it.equals("a") }.length
}
return 0
}
It shows that it.equals("a") could be improved, with the message
Call replaceable with binary operator
So I just use Alt-Enter to change it accordingly and get
fun process(string: String?): Int {
if (string != null) {
return string.filter { it == "a" }.length
}
return 0
}
Unfortunately now it error stating
Operator '==' cannot be applied to Char and String.
I assume this is a bug in the proposed optimization?
Just to be sure we're on the same page, it is a Char because the filter method that you use operates on the string as a sequence of characters.
Therefore, it.equals("a") is effectively comparing a Char with a String. This can never be true, because a string can never be equal to any character, even if it contains only one. So the code doesn't work in either case, unless you change your string "a" to the character 'a'.
Even if the operator == is compiled to the equivalent equals() method call, the compiler has additional checks in the operator form compared to explicit method calls. The error you get is because the == operator requires a type match, as opposed to its method counterpart equals(). (Since "a" is a string, you can't use the operator to compare it with the character it).
Why the difference? You may ask.
As far as I understood, the Kotlin team followed the Java convention for the method equals and left its contract permissive by allowing Any? as parameter. This is probably because of constraints of interoperability with Java.
However, they still saved us from this kind of mistakes with the additional type safety of the operator.
I have to admit, though, that the IDE should give you a warning for your incorrect equals call before asking you to replace the method call by an operator.

What is the difference between require and assert?

With Kotlin 1.3 came a new feature, contracts, and with them the function require(), but it seems pretty similar to assert(). Here is what their KDoc says:
require(value: Boolean): Throws an IllegalArgumentException if the value is false.
assert(value: Boolean): Throws an AssertionError if the value is false and runtime assertions have been enabled on the JVM using the -ea JVM option.
So when should I use require() and when should I use assert()?
require and assert work differently. For this, you need to dive into the code.
assert(condition) calls a different method internally, which is where you see the actual code:
#kotlin.internal.InlineOnly
public inline fun assert(value: Boolean, lazyMessage: () -> Any) {
if (_Assertions.ENABLED) {
if (!value) {
val message = lazyMessage()
throw AssertionError(message)
}
}
}
AFAIK, this ties to the -ea flag; if -ea isn't present (or disabled), assert will not throw an exception.
As a result, this will not compile:
fun something(string: String?){
assert (string != null)
nonNull(string) // Type mismatch
}
fun nonNull(str: String){}
This is where require comes in. require(condition) also calls a different method under the hood. If you replace assert with require, you'll see that smart cast will successfully cast it as non-null, because require is guaranteed to throw an exception if the condition fails.
#kotlin.internal.InlineOnly
public inline fun require(value: Boolean, lazyMessage: () -> Any): Unit {
contract {
returns() implies value
}
if (!value) {
val message = lazyMessage()
throw IllegalArgumentException(message.toString())
}
}
The boolean-only function does the contract too, then calls that method if the contract fails.
Contracts are new, and I am not entirely sure how they work, but this is how I understand it:
The implies keyword is an infix fun; what this does is that it tells the compiler the condition is true if it returns from the method. This helps with auto-casting, like in the example I mentioned earlier. It doesn't actually cause the method to return (or at least that's what my current testing points to), but it's for the compiler.
It's also readable: returning implies condition is true
That's the contact part: the exception here is always thrown, as you can see by the condition. require uses if(!value), where as assert checks if(_Assertions.ENABLED && !value).
This isn't the only use for require though. It can also be used for validation of arguments. I.e. if you have this:
operator fun get(index: Int) : T {
if (index < 0 || index >= size)
throw IllegalArgumentException("Index out of range")
// return here
}
You could replace it with:
operator fun get(index: Int) : T {
require (index >= 0 && index < size) { "Index out of range" }
// return here
}
There are a lot different uses for this, but these are just some examples.
What this means:
assert is like in Java; it is only triggered if assertions are enabled. Using it does not guarantee the condition is met.
require always works, regardless of VM flags
Which means require can be used to help the compiler with i.e. smart cast, and it's better to use than assert for making sure arguments are valid. And since it also works regardless of VM flags, it can be used outside debugging cases, as forpas mentioned. If you're making a library written in Kotlin, you can replace argument checking with manual throwing with require, and it will still work. Obviously, this assumes Kotlin 1.3.0, but that's beside the point.
And it can be used internally to ensure smart cast works as expected, but throw an exception if the condition isn't met.
To answer your question though:
Use require when you want to to argument checking, even if it's in production.
Use assert if you're doing local debugging, and have the -ea flag enabled.
Let's say you want a function to calculate n! (factorial) like this:
fun factorial(n: Long): Long {
require(n >= 0) { "Number must not be negative" }
// code
}
In this case require() checks the validity of the argument passed to the function and throws an IllegalArgumentException if the argument is not what it's supposed to be and for debugging you also have the explanatory message.
On the other hand assert() can be used anywhere in your code to make your own specialized checks if runtime assertions have been enabled.
There is also
check(Boolean) throws IllegalStateException when its argument is false,
which is used to check object state.
So each of the above has its own place in your code and you can use it if you find it useful.

Elvis Operator vs Non-Null Assertion: Diff Between These Statements?

Trying to understand null safety in Kotlin: both of these following statements seem to work fine and be interchangeable in my program:
var y1: Double = 0.0
get() = when(hasParent) {
true -> parent!!.y1
else -> field
}
and
var y1: Double = 0.0
get() = parent?.y1!!
(hasParent is simply a getter to see if parent is null or not)
Are these two semantically the same or are they actually different expressions that mean different things? And if they mean the same thing semantically, is the first ever preferred over the second for any reason?
In this case you don't need hasParent. The form which is applicable is this:\
var y1: Double = 0.0
get() = parent?.y1 ?: field
The problem with your second getter is that it will try to return the parent.y1 no matter what and it will throw a NullPointerException if it is not there.
If you use IDEA you'll get warnings for these kinds of problems so they are an easy fix, but you need to be aware of the so called platform types which come from Java code:
val queue: Queue<String> = LinkedList()
queue.peek().toInt()
Here the compiler won't complain for .toInt() although it is possible to get a null from the Queue. I've written about this here.
Note that jingx's and Adam Arold's answer is good for the current situation, but it wouldn't be equivalent to your first snippet if the type of y1 was nullable: if parent is not null, but parent.y1 is, then your code gives null and parent?.y1 ?: field gives field.
I'd say the actual preferred form if you need the first behavior is
if (parent != null) parent.y1 else field // if parent is val without a custom getter
parent.let { if (it != null) it.y1 else field } // otherwise
Using hasParent hides from the compiler that you actually checked for null and don't need !!.

Kotlin: check if a nullable value is valid in an if statement

Ideally, I think the commented-out if statements make more sense, at least to me. I mean, if someone asks me if null is bigger than 0, than I would answer no. Or if null is true, then also no. But those did not work as I expected, and throw compilation errors. So, I have changed those like below. But those do not look good or concise. Is there a better way to handle these?
class Result(val code:Int)
{
}
fun getResult():Result?
{
return null;
}
fun main(args: Array<String>)
{
var result = getResult();
var success:Boolean? = null;
//if(result?.code > 0)
if(result?.code?:0 > 0)
{
print("Good.");
}
//if(success)
if(success == true)
{
print("Good.");
}
}
The > is compiled to a call of compareTo(other: Int), which works by convention (its defined as an operator on Int). You cannot invoke this function on nullable Int? though.
There'd be a workaround: Create another extension on Int?:
operator fun Int?.compareTo(other: Int): Int =
(this ?: 0).compareTo(other)
Now your call does work:
if (result?.code > 0)
print("Good.")
the nullable element is actually the Result instance itself, not its code property.
i think using let in combination with the safe-get operator on the result more accurately reflects the design of the code:
result?.let {
if(it.code > 0) {
}
}
The reason the commented-out code did not compile is because result?.code is nullable and you can't call comparing operator (i.e > in this case) on a nullable expression because they don't type match. (it is defined to only accept non-nullable types)
if null is bigger than 0, than I would answer no. Or if null is true, then also no
Kotlin completely disambiguates between nullable and non-nullable entity. So, at compile time kotlin compiler refuses to compile if you are comparing something with a nullable type, to avoid run time exception ahead of time. In java,
Integer x = null;
System.out.println(x > `)
this compiles but throws a NullPointerException on runtime, which you obviously do not want. Kotlin compiler is just being smart here to avoid such runtime exceptions by refusing to compile.
Now onto the better way to deal with it, like everyone said, using let is an appropriate way. A simpler way can be a regular null check with if expresion
if(result != null && result.code > 0) {
print("Good.");
}
result?.code > 0
It's not working because > internally calls compareTo() method. compareTo() method does not work on a nullable object. That's why you have to add elvis operator(?:) on variable code to assign a value if the code variable is null. So that the value is not null and then compareTo() method works.
result?.code?:0 > 0
I have added a let to solve. If the result is not null then we will execute the code within the let block. Please check the updated code.
class Result(val code:Int){
}
fun getResult():Result?{
return null;
}
fun main(args: Array<String>){
var result = getResult();
var success:Boolean? = null;
//if(result?.code > 0)
if(result?.code?:0 > 0){
print("Good.");
}
// Updated Code
result?.let{
if(result.code > 0)
print("Good.")
}
//if(success)
if(success == true){
print("Good.");
}
}

XTend null safe throws NullPointerException

I am porting my template code to XTend. At some point I have this type of condition handling in a test case:
#Test
def xtendIfTest() {
val obj = new FD
if (true && obj?.property?.isNotNull) {
return
}
fail("Not passed")
}
def boolean isNotNull(Object o) {
return o != null
}
class FD {
#Accessors
String property
}
This works as expected as the property is null and the test will fail with "Not passed" message. But a simple change in the return type of isNotNull method to Boolean (wrapper):
def Boolean isNotNull(Object o) {
return o != null
}
fails with a NullPointerException. Examining the generated java code for this I can see that XTend is using an intermediate Boolean object expression and that is the cause of NPE. Am I missing the point of the XTend null safe operator (?.) or I can't use a method like this after the operator?
Thanks.
The operator behaves properly. The exception is thrown because of the usage of a Boolean in an if-expression, which requires auto-unboxing.
If you try the following:
#Test
def xtendIfTest() {
val Boolean obj = null
if (obj) {
return
}
fail("Not passed")
}
You will also run into a NullPointerException.
This is consistent with the Java Language Specification (https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.8) - when auto-unboxing is required this can yield a NullPointerException:
#Test
public void test() {
Boolean value = null;
if (value) { // warning: Null pointer access: This expression of type Boolean is null but requires auto-unboxing
// dead code
}
}
Hope that helps.
Short answer: Change the second null-safe call to a regular call.
I.e. change
obj?.property?.isNotNull
to this:
obj?.property.isNotNull
Long answer:
The docs describe the null-safe operator thusly:
In many situations it is ok for an expression to return null if a
receiver was null
That means the second call in your example, property?. won't even call isNotNull if the left side of the call was null. Instead, it will return null. So the conditional "effectively" evaluates to:
if (true && null) { // causes NPE when java tries to unbox the Boolean
(By the way - the true is superfluous in this context, but I'm keeping it just in case you had another condition to check - I'm assuming you're just simplifying it to true for this example.)
If you make the change I'm suggesting, obj?.property will be evaluated, then the result will be passed to isNotNull, evaluating to this:
if (true && isNotNull(null)) {
which returns the proper Boolean object that will be auto-unboxed as expected.
A Word of Caution
In your first form of isNotNull, i.e. the one returning primitive boolean, you should actually get a warning like "Null-safe call of primitive-valued feature isNotNull, default value false will be used".
This is because you're stretching the intent of the null-safe call, which is to return null without invoking the right side method if the left side of the operator was null. But if your isNotNull returns a primitive boolean, the whole expression obviously can't evaluate to null, so Xtend uses a default instead, which is false for booleans.
To emphasize the problem in a different way - it evaluates to false without calling isNotNull - that means even if you used a method isNull after the operator, it would still return false!
The docs also mention this behavior (albeit in general terms):
For primitive types the default value is returned (e.g. 0 for int).
This may not be what you want in some cases, so a warning will be
raised by default
So I recommend always using a non-primitive return value on the right-hand side of a null-safe call. But if you're going to convert the isNotNull to a regular call as I suggested, this rule doesn't apply, and either return type is fine.