Immutable val null check inside extension function - kotlin

When I have an immutable val optional, the compiler tracks the information about the check I performed for null and can treat the variable as non null and call it directly inside the if condition.
val s: String? = "test"
if (s != null) {
s.startsWith("3") // This works
}
if (!s.isNullOrEmpty()) {
s.startsWith("3") // Not working
}
Is it possible to make that check in an extension function and keep the compiler aware of it?

This is not yet available in Kotlin.
There is a feature called "Contracts" which is currently developed at JetBrains (https://discuss.kotlinlang.org/t/status-of-kotlin-internal-contracts/6392) – it's similar to what they've done with their own #Contract annotation for Java code, but will have support from the compiler.
However, it's in early stages and there is no release date yet.

Related

Interoperability java-kotlin Nullable string crashing at runtime but why?

I have an alternative to my problem, but I still have 2 questions:
Why it's crashing
Why Intellij/compiler is not complaining
I provided a small example of my issue. Here is an overview (you can find the code just after)
Car.java is the java class with a simple getter annoted as nulllable
MyView.kt is the crashing at runtime example with no warning in Intellij or in gradle. (Crashing when the value is null)
MyView2.kt is not crashing at runtime (even if mType is null)
Library.kt (kotlin stdlib) is simply the expected call for the example (even if it's weird to see string.toString())
Car.java
#Nullable
private String mType;
#Nullable
public String getCarType() {
return mType;
}
MyView.kt (crashing)
val test: String = myCar.carType.toString()
MyView2.kt (not crashing)
val carType: String? = myCar.carType
val test2: String = carType.toString()
Library.kt (kotlin stdlib)
/**
* Returns a string representation of the object. Can be called with a null receiver, in which case
* it returns the string "null".
*/
public fun Any?.toString(): String
Thanks! I guess this is a corner case of the interop between kotlin and java? Or... someone is aware of a better explanation?
The clue to this difference is the optional marker ? in this line in MyView2.kt
val carType: String? = myCar.carType
- here you are declaring to the Kotlin compiler that you know that carType is nullable. (In turn the behaviour of .toString() will work even though it is called on a null object, as you showed from the docs.)
However things are different in MyView.kt because the code doesn't get as far as the .toString() call. Here you are directly using a platform type (i.e. Java) where null-safety rules cannot be deduced.
This documentation about Calling Java code from Kotlin explains:
Types of Java declarations are treated in Kotlin in a specific manner and called platform types. Null-checks are relaxed for such types, so that safety guarantees for them are the same as in Java

Kotlin Operators ?, ?., ?: open source implementation

I am pretty new to Kotlin, I am looking at the null safety and Elvis operators and would like to know more on how these are implemented to work on top of JVM.
Operators I am interested to know the implementation of:
? ?. ?:
But I am unable to locate any source associated with these. Are the implementations hidden? From my IDE also I cannot locate any source related to these, magic?
From the Kotlinlang.org: It specifies that Kotlin is an open source language: Kotlin is an open-source statically typed programming language that targets the JVM, Android, JavaScript and Native
Note: I know I don't need to specify null on the right hand side of the Elvis, this is just to send my point across in the screen grab.
Disclaimer: I'm no expert on the Kotlin compiler. I just looked at the source code.
The tokens are defined here:
KtSingleValueToken SAFE_ACCESS = new KtSingleValueToken("SAFE_ACCESS", "?.");
KtSingleValueToken ELVIS = new KtSingleValueToken("ELVIS", "?:");
KtSingleValueToken QUEST = new KtSingleValueToken("QUEST", "?");
These tokens are parsed by the Kotlin compiler itself, they are not defined in Java. This is why you cannot jump to a definition - they are re-written by the compiler.
I don't know how they are implemented, but checking out the Kotlin source and using the above tokens as a starting point might be useful.
Those features are "embedded" into the language. So you can't really dig into the code at compile time. An equivalent example to this would be trying to get the implementation of a while loop or a when statement. Those are language features that just generate compiled code
One thing that you could do if you're curious would be to decompile a simple program using them and check the result. However, as the generated bytecode may include some optimizations, the result might differ between different use cases.
The most important thing you need to know is what they do and how to use them. You can find an example of equivalent behaviour between null safe operators and java code in the Kotlin Koans, in which this Java code
public void sendMessageToClient(
#Nullable Client client,
#Nullable String message,
#NotNull Mailer mailer
) {
if (client == null || message == null) return;
PersonalInfo personalInfo = client.getPersonalInfo();
if (personalInfo == null) return;
String email = personalInfo.getEmail();
if (email == null) return;
mailer.sendMessage(email, message);
}
can be rewritten in Kotlin as
val email = client?.personalInfo?.email
if (email != null && message != null) {
mailer.sendMessage(email, message)
}
You don't have to set null on the right side of the elvis operator, the elvis operator is for handling non nullable case.
val info:EuiccInfo? = msg?.euiccInfo
val info - defined as nullable so it can be set null as well, if msg is null (msg? means msg can be null too, and if msg is null it will not access to .euiccInfo) info will be null.
lets assume info defined as non nullable val
val info:EuiccInfo = msg?.euiccInfo
compiler will not allow you to set info null value because msg is nullable,
so you have to handle non null case.
val info: EuiccInfo = msg?.euiccInfo ?: someDefaultNonNullValue (EuiccInfo())
it's unnecessary (and nonsense) to handle null case with Elvis operator because it will be set null if msg is null or msg?.euiccInfo is null.

ArgumentMatcher for Kotlin

I'm trying to use ArgumentMatcher in my tests. I do next:
Mockito.`when`(someRepository.save(
argThat { it.name == someName } // Here I want to do mock for all objects with name someName
)).thenReturn(save(someEntity))
And I get next error: Type inference failed: Not enough information to infer parameter T in fun when(p0: T!): OngoingStubbing!
How properly write ArgumentMatcher in Kotlin?
I strongly recommend using nhaarman's mockito-kotlin instead of vanilla Mockito. It has numerous advantages that allow it to be used with fewer issues in Kotlin as Mockito is designed for use in Java. You can see this guide for how to use argument matchers in Kotlin. Your example will look very similar, but should have less issues with type inference.
I found a solution by adding ArgumentMatcher from java class. My IDE converted it to Kotlin:
In java:
Mockito.when(someRepository.save(ArgumentMatchers.argThat(entity-> entity.getName().equals("someName")
&& entity.getDescription().equals("somedescritpion")
))));
In Kotlin:
Mockito.`when`<Any>(someRepository.save(ArgumentMatchers.argThat { (name, _, description, ) ->
(name == "someName" && description == "somedescritpion"
)
}))
Note: You should add _ if you have some fields which you don't want to consider in the matcher.
Use the someRepository.save(Mockito.any<String>()) . That would not care about what argument you are passing as long as it is a String. Empty values count too.

Migrate Java Option call to kotlin

I'm taking my first steps with kotlin.
I am migrating some my existing java code to kotlin.
I have the folllowing line:
storyDate.ifPresent(article::setPublishDate);
Where storyDate is an Optional and article has a method setPublishDate(Date) method.
How would I migrate this line to kotlin?
The auto migrator at https://try.kotlinlang.org is
storyDate.ifPresent(Consumer<Date>({ article.setPublishDate() }))
But this line doesn't compile with the kotlin compiler.
I strongly prefer using extension functions and extension fields, so I've written smth like
val <T> Optional<T>.value: T?
get() = orElse(null)
And then you can use it anywhere (after import) like
myOptional.value?.let {
// handle here
}
It’s rather uncommon to use Optional in Kotlin. If you can make storyDate work as an ordinary unwrapped type, such constructs can often be expressed with a simple let call:
storyDate?.let {
article.setPublishDate(it)
//probably property access works as well:
article.publishDate = it
}
How it works: The safe call ?. will invoke let only if storyDate is not null, otherwise the whole expression evaluates to, again, null. When the variable is not null, let is called with a simple lambda where storyDate is accessible by it (or you can rename it to whatever you like).
Side note:
If storyDate really must be Optional, you can still use the depicted construct by unwrapping it like this:
storyDate.orElse(null)?.let {}
storyDate.ifPresent { Article.setPublishDate(it) }
or
storyDate.ifPresent(Article::setPublishDate)
will work.
In the first example, it denotes the value in the optional instance, which is the Date in the optional storyDate.
I assumed that Article is a class, which has the setPublishDate(Date) static method, because class names are always capitalized.
But if article is an instance, not a class, and it has non-static method, then the following will work.
// article = Article(/* some Article-typed object */)
storyDate.ifPresent { article.setPublishDate(it) }
it has the same meaning as the above one, i.e., the actual Date value in Optional.

Errors when converting Java to Kotlin code

So this is my Java code that works
if (currentForecastJava.getCurrentObservation().getTempF() >= 60) {
mCurrentWeatherBox.setBackgroundColor(getResources().getColor(R.color.weather_warm));
mToolbar.setBackgroundColor(getResources().getColor(R.color.weather_warm));
} else {
mCurrentWeatherBox.setBackgroundColor(getResources().getColor(R.color.weather_cool));
mToolbar.setBackgroundColor(getResources().getColor(R.color.weather_cool));
}
What I am trying to do is write this in Kotlin(know AS has the converter but does not change anything)
if (currentObservationKotlin.tempF.compareTo() >=)
currentWeatherBox.setBackgroundColor(resources.getColor(R.color.weather_warm))
toolbar.setBackgroundColor(resources.getColor(R.color.weather_warm))
else currentWeatherBox.setBackgroundColor(resources.getColor(R.color.weather_cool))
toolbar.setBackgroundColor(resources.getColor(R.color.weather_cool))
I know I need a value in the compareTo() and after but I am not really sure what to place as I want to compare TempF to 60 as I want the color to change based on the TempF value from data class. I do not have another object to compare it to.
I can write this in Java and it works with the rest of the Kotlin code but trying to see if Kotlin can make the Java if/else similar and quicker to write.
The Java and Kotlin version would be almost the same. Start with the Java code and drop the semicolons ; and then anything that COULD be nullable needs to be handled with either null checks or you asserting that they will never be null with !!, or using another null operator. You do not show enough code (i.e. the method signature coming into this code, or the declaration of the used variables) to tell you exactly what needs to change.
For handling null values see: In Kotlin, what is the idiomatic way to deal with nullable values
You might end up with warnings around calling a setter method as something.setXyz(value) instead of assigning it as a property something.xyz = value and the IDE will help you fix those or you can live with the warning.
For more about interoperability with JavaBean properties see: Java Interop: Getters and Setters
So with all of that in mind, your final code (with a little more cleaning) might appear something like:
val currentTemp = currentForecastJava.getCurrentObservation()?.getTempF() ?: -1
// or change -1 to whatever default you want if there is no observation
if (currentTemp >= 60) {
val warmColor = getResources().getColor(R.color.weather_warm)
mCurrentWeatherBox.backgroundColor = warmColor
mToolbar.backgroundColor = warmColor
} else {
val coolColor = getResources().getColor(R.color.weather_cool)
mCurrentWeatherBox.backgroundColor = coolColor
mToolbar.backgroundColor = coolColor
}