Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin contract infer return value instead of argument value

I have a function that looks something like:

fun MyInput?.toOutput() : Output? {
  if (this == null) return null
  return Output(this.someValue)
}

In places where I know that my MyInput is non-null (for example, inside a method that takes a input: MyInput as an arg), I'd like to be able to use input.toOutput as Output instead of Output?

I've tried using

contract {
  returnsNotNull() implies (this@toOutput != null)
}

But that has the implication backwards. That tells me that if toOutput returns a non-null type, that my input was non-null. I want to tell the analyzer things about the return value based on the arguments. In Java, I could use org.jetbrains.annotations.@Contract("null -> null ; !null -> !null") to accomplish this.

Is there a way to do this in Kotlin?

like image 470
karl Avatar asked Apr 25 '19 16:04

karl


1 Answers

You don't need contracts for this. You just need to make a non-nullable overload. Like this:

fun MyInput?.toOutput(): Output? {
  if (this == null) return null
  return Output(this.someValue)
}

fun MyInput.toOutput(): Output = Output(this.someValue)

However, this will not work out of the box on the JVM, because the function signatures will clash. To make it work, you have to give one of the functions a new name with the @JvmName annotation. For example:

@JvmName("toOutputNonNull")
fun MyInput.toOutput(): Output = Output(this.someValue)

You will still be able to call it like input.toOutput() from Kotlin, but it will become something like FileNameKt.toOutputNonNull(input) if you call it from Java.

like image 195
marstran Avatar answered Nov 17 '22 17:11

marstran