Retain smartcast when creating custom extension - kotlin

I currently have to write
val myList: List<Int>? = listOf()
if(!myList.isNullOrEmpty()){
// myList manipulations
}
Which smartcasts myList to no non null. The below do not give any smartcast:
if(!myList.orEmpty().isNotEmpty()){
// Compiler thinks myList can be null here
// But this is not what I want either, I want the extension fun below
}
if(myList.isNotEmptyExtension()){
// Compiler thinks myList can be null here
}
private fun <T> Collection<T>?.isNotEmptyExtension() : Boolean {
return !this.isNullOrEmpty()
}
Is there a way to get smartCasts for custom extensions?

This is solved by contracts introduced in Kotlin 1.3.
Contracts are a way to inform the compiler certain properties of your function, so that it can perform some static analysis, in this case enable smart casts.
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
#ExperimentalContracts
private fun <T> Collection<T>?.isNotEmptyExtension() : Boolean {
contract {
returns(true) implies (this#isNotEmptyExtension != null)
}
return !this.isNullOrEmpty()
}
You can refer to the source of isNullOrEmpty and see a similar contract.
contract {
returns(false) implies (this#isNullOrEmpty != null)
}

Related

Can I use a Kotlin Contract to guarantee the non-nullity of another property?

I have a class with a nullable property description: String?, and for convenience would like to expose a fun hasDescription(): Boolean that null-checks said String.
For even more convenience, I am hoping to use a contract so I can smart cast description to non-nullable String after checking hasDescription().
Is this possible now (with experimental contracts, and Kotlin 1.5)?
Might it be possible when contracts go stable?
data class Widget (
val description: String? = null,
)
class Gadget {
val widget: Widget? = null
val description: String? get() = widget?.description
#ExperimentalContracts
fun hasDescription(): Boolean {
// Error in contract description: only references to
// parameters are allowed in contract description
contract {
returns(true) implies((this#Gadget).description is String)
}
return this.description != null
}
}
#ExperimentalContracts
fun testContract(gadget: Gadget) {
if (gadget.hasDescription()) {
// Error: Type mismatch (String? for String)
// expected, since the contract itself does not compile
val description: String = gadget.description
}
}
In short, it's not possible.
Contracts primarily consider the behavior of methods rather than the properties of values. Properties of values should be handled by the type system rather than contracts.
And yes, it might be implemented in the future.
It doesn't mean that if something potentially can be handled by the type system, then it is out of contracts' scope.
https://github.com/Kotlin/KEEP/blob/master/proposals/kotlin-contracts.md#scope-and-restrictions
Alternatives
Nulls are well handled in Kotlin's type system, and so we can use that to check for nullability.
Smart casting
Using smart-casting would remove the need for Contracts and the hasDescription()
method.
fun nullCheckWhen(gadget: Gadget) {
when (val description = gadget.description) {
null -> println("description is null")
else -> println("description.length ${description.length}")
}
}
fun earlyReturn(gadget: Gadget) {
val description = gadget.description ?: return
println("description.length ${description.length}")
}
fun forcefulNullCheck(gadget: Gadget) {
val description = requireNotNull(gadget.description) {
"description must not be null"
}
println("description.length ${description.length}")
}
fun elvisScopeFunctionNullSafe(gadget: Gadget) {
gadget.widget?.description?.let { description ->
println("description.length ${description.length}")
}
}
These are a little more clunky, and not as pretty as Contracts could be - but at least they work.
In fact, some of them use Kotlin Contracts, but of course they can only work on method parameters.
Preconditions.kt
/**
* Throws an [IllegalArgumentException] if the [value] is null. Otherwise returns the not null value.
*/
#kotlin.internal.InlineOnly
public inline fun <T : Any> requireNotNull(value: T?): T {
contract {
returns() implies (value != null)
}
return requireNotNull(value) { "Required value was null." }
}
Type hierarchies
I don't think this approach is applicable to your situation, but I thought I'd share it as it can be useful.
If description was defined in an interface as a String?, then Widget could implement description as a non-nullable String. This works because in Kotlin the nullable type is a super-type of the non-nullable type. Any implementation of description can choose to be either be String? or String.
interface Component {
val description: String?
}
data class Widget(
override val description: String
) : Component
data class Greeble(
override val description: String?
) : Component
fun nullCheckGeneric(component: Component) {
when (component) {
is Widget ->
// no need for a null check
println("description.length ${component.description.length}")
is Greeble ->
// description is nullable
println("description.length ${component.description?.length}")
}
}

How can I let the Kotlin compiler know I already checked for null inside a function?

Basically I have a function that does some stuff but specifically it checks if two values I'm passing are null. This function is called from various places to make sure those two values are not null. Kotlin is complaining later that I'm not checking for null. Is there a way I can do this so that Kotlin already knows that I am checking for null without using !!?
Here is a simple example:
private fun stuff() {
var possibleNull: String? = "test"
if (testNull(possibleNull)) {
mustPassNonNull(possibleNull)
}
}
private fun mustPassNonNull(possibleNull: String) {
//use value that isn't null
}
private fun testNull(possibleNull: String?): Boolean {
return possibleNull != null
}
Basically testNull is only true if possibleNull is not null and that check is on an if right before calling mustPassNonNull so can I let Kotlin know I'm already checking that? without using !! of course.
Thanks.
It is possible with the use of contracts. Currently in experimental in Kotlin 1.3.
It is possible to declare contracts for your own functions, but this feature is experimental, as the current syntax is in a state of early prototype and will most probably be changed. Also, please note, that currently the Kotlin compiler does not verify contracts, so it's a programmer's responsibility to write correct and sound contracts. -kotlinlang.org
#ExperimentalContracts
fun stuff() {
var possibleNull: String? = "test"
if (testNull(possibleNull)) {
mustPassNonNull(possibleNull)
}
}
fun mustPassNonNull(possibleNull: String) {
//use value that isn't null
}
#ExperimentalContracts
fun testNull(possibleNull: String?): Boolean {
contract{
returns(true) implies (possibleNull is String)
}
return possibleNull != null
}
Articles I referenced:
https://kotlinlang.org/docs/reference/whatsnew13.html
https://blog.kotlin-academy.com/understanding-kotlin-contracts-f255ded41ef2
It seems like a simple let situation
private fun stuff() {
var possibleNull: String? = "test"
possibleNull?.let { mustPassNonNull(it) }
}
This way mustPassNonNull will know that it isn't null :)
Also, if you need to do more than just check for nullability you could do:
possibleNull
?.takeIf { /* it's not null here anymore, add any checks you need */}
?.let { /* both non-null and checked for whatever you need */}

Java8 Higher-Order Functions and Kotlin Lambdas interoperability

I have a Java example where a method is implemented as
#Override
public Function<ISeq<Item>, Double> fitness() {
return items -> {
final Item sum = items.stream().collect(Item.toSum());
return sum._size <= _knapsackSize ? sum._value : 0;
};
}
IntelliJ's automatic translation of it to Kotlin is
override fun fitness(): Function<ISeq<Item>, Double> {
return { items:ISeq<Item> ->
val sum = items.stream().collect(Item.toSum())
if (sum.size <= _knapsackSize) sum.value else 0.0
}
}
(I made the type of items explicit and changed return to 0.0)
Still I see that there are compatibility problems with Java's Function and Kotlin native lambdas, but I'm not that the most familiar with these. Error is:
Question is: is it possible to override in Kotlin the external Java library's fitness() method on this example and if so how ?
Problem:
You are returning a (Kotlin) lambda ISeq<Knapsack.Item> -> Double. But this is not what you want. You want to return a Java Function<ISeq<Knapsack.Item>, Double>.
Solution:
You can use a SAM Conversion to create a Function.
Just like Java 8, Kotlin supports SAM conversions. This means that
Kotlin function literals can be automatically converted into
implementations of Java interfaces with a single non-default method,
as long as the parameter types of the interface method match the
parameter types of the Kotlin function.
I created a minimal example to demonstrate that. Consider you have a Java class like this:
public class Foo {
public Function<String, Integer> getFunction() {
return item -> Integer.valueOf(item);
}
}
If you want to override getFunction in Kotlin you would do it like this:
class Bar: Foo() {
override fun getFunction(): Function<String, Int> {
return Function {
it.toInt()
}
}
}
When returning lambda as Java's functional interface, you have to use explicit SAM constructor:
override fun fitness(): Function<ISeq<Item>, Double> {
return Function { items:ISeq<Item> ->
val sum = items.stream().collect(Item.toSum())
if (sum.size <= _knapsackSize) sum.value else 0.0
}
}
Also don't forget to import java.util.function.Function since Kotlin has its own class of that name

Kotlin: Check if lazy val has been initialised

Is there a way to tell if a lazy val has been initialised in Kotlin without initialising it in the process?
eg if I have a lazy val, querying if it is null would instantiate it
val messageBroker: MessageBroker by lazy { MessageBroker() }
if (messageBroker == null) {
// oops
}
I could potentially use a second variable, but that seems messy.
private var isMessageBrokerInstantiated: Boolean = false
val messageBroker: MessageBroker by lazy {
isMessageBrokerInstantiated = true
MessageBroker()
}
...
if (!isMessageBrokerInstantiated) {
// use case
}
Is there some sexy way of determining this, like if (Lazy(messageBroker).isInstantiated())?
Related (but not the same): How to check if a "lateinit" variable has been initialized?
There is a way, but you have to access the delegate object which is returned by lazy {}:
val messageBrokerDelegate = lazy { MessageBroker() }
val messageBroker by messageBrokerDelegate
if(messageBrokerDelegate.isInitialized())
...
isInitialized is a public method on interface Lazy<T>, here are the docs.
Since Kotlin 1.1, you can access a property delegate directly using .getDelegate().
You can write an extension property for a property reference that checks that it has a Lazy delegate that has already been initialized:
/**
* Returns true if a lazy property reference has been initialized, or if the property is not lazy.
*/
val KProperty0<*>.isLazyInitialized: Boolean
get() {
if (this !is Lazy<*>) return true
// Prevent IllegalAccessException from JVM access check on private properties.
val originalAccessLevel = isAccessible
isAccessible = true
val isLazyInitialized = (getDelegate() as Lazy<*>).isInitialized()
// Reset access level.
isAccessible = originalAccessLevel
return isLazyInitialized
}
Then at the use site:
val messageBroker: MessageBroker by lazy { MessageBroker() }
if (this::messageBroker.isLazyInitialized) {
// ... do stuff here
}
This solution requires kotlin-reflect to be on the classpath. With Gradle, use compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
The isAccessible = true part is required for the .getDelegate(), because otherwise it cannot access the private field storing the delegate reference.
Testing if the lazy property is easy enough:
import kotlin.reflect.KProperty0
import kotlin.reflect.jvm.isAccessible
val KProperty0<*>.isLazyInitialized: Boolean
get() {
// Prevent IllegalAccessException from JVM access check
isAccessible = true
return (getDelegate() as Lazy<*>).isInitialized()
}
…but you can make it even easier to reference a property without initializing it:
/**
* Returns the value of the given lazy property if initialized, null
* otherwise.
*/
val <T> KProperty0<T>.orNull: T?
get() = if (isLazyInitialized) get() else null
Now you can do things like:
private val myList by lazy {
mutableSetOf<String>()
}
fun add(str: String) {
// Create the list if necessary
myList += str
}
fun remove(str: String) {
// Don't create the list
::myList.orNull?.remove(str)
}
fun clear() {
// Don't create the list
::myList.orNull?.clear()
}

Conditional side-effects and optional types in Kotlin

I am trying to perform a simple side-effect in Kotlin:
fun handle(request: Request) {
repository.findByUID(request.userId)?.let {
if (someCondition) return
service.run(...)
}
}
As you can see, the side-effect should be performed when the repository returns a non-null value and when someCondition is satisfied.
Is there any Kotlin-way of doing this rather than using if{}-return constructs?
In Java 8, it could be achieved by:
optional
.filter(...)
.ifPresent(...)
Update:
Kotlin 1.1 has a method called takeIf:
/**
* Returns `this` value if it satisfies the given [predicate] or `null`, if it doesn't.
*/
#kotlin.internal.InlineOnly
#SinceKotlin("1.1")
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? = if (predicate(this)) this else null
You can use it this way:
repository.findByUID(request.userId)?.takeIf { someCondition }?.let { service -> }
Kotlin doesn't contain such method in the stdlib.
However, You can define it:
inline fun <K : Any> K.ifPresent(condition: K.() -> Boolean): K? = if (condition()) this else null
Using this method your example can be rewritten as:
fun handle(request: Request) {
repository.findByUID(request.userId)?.ifPresent { someCondition }?.let {
service.run(...)
}
}
Another option may be to use the built in extensions for list (but there is an overhead of using lists):
listOf(repository.findByUID(userId)).filter { someCondition }.forEach { service.run(...) }
Kotlin's nullable types are very similar to Java's Optional (which is very similar to Guava's Optional).
In Kotlin 1.1 you can use takeIf which "is like filter for a single value" (takeIf() and also() - What's New in Kotlin 1.1 - Kotlin Programming Language):
repository.findByUID(request.userId).takeIf { !someCondition }?.let { service.run(...) }
Kotlin 1.0 does not define map, flatMap, filter/takeIf, etc. for nullable types but you can easily define your own function. e.g.:
inline fun <T> filter(value: T?, predicate: (T) -> Boolean): T? {
return if (value != null && predicate(value)) value else null
}
Example usage:
filter(repository.findByUID(request.userId)) { !someCondition }?.let { service.run(...) }
I would go without extra libs nor extension functions with this construct:
?.let { if (someCondition) null else it }
After aplying this construct on the code sample from the original question, it would look like:
fun handle(request: Request) {
repository.findByUID(request.userId)
?.let { if (someCondition) null else it }
?.let {
service.run {
/* ... */
}
}
}
Or at least it looks OK, compiles and have same types in my codebase after defining Request, repository, findByUid etc. :-)