How can I tell kotlin that the function does not return null if the parameter is non-zero?

I want to write a convenience extension to extract values ​​from the Map while analyzing them. If the parsing fails, the function should return the default value. All this works fine, but I want to tell the Kotlin compiler that when the default value is not null, the result will also not be zero. I could do this in Java via annotation @Contract, but it doesn't seem to work in Kotlin. It can be done? Do expansion function contracts work? Here is a Kotlin attempt:

import org.jetbrains.annotations.Contract

private const val TAG = "ParseExtensions"

@Contract("_, !null -> !null")
fun Map<String, String>.optLong(key: String, default: Long?): Long? {
    val value = get(key)
    value ?: return default

    return try {
        java.lang.Long.valueOf(value)
    } catch (e: NumberFormatException) {
        Log.e(TAG, e)
        Log.d(TAG, "Couldn't convert $value to long for key $key")

        default
    }
}

fun test() {
    val a = HashMap<String, String>()

    val something: Long = a.optLong("somekey", 1)
}

IDE something, , optLong 1. , Java:

public class StackoverflowQuestion
{
    @Contract("_, !null -> !null")
    static @Nullable Long getLong(@NonNull String key, @Nullable Long def)
    {
        // Just for testing, no real code here.
        return 0L;
    }

    static void testNull(@NonNull Long value) {
    }

    static void test()
    {
        final Long something = getLong("somekey", 1L);
        testNull(something);
    }
}

. @Contract , IDE testNull() .

+4
2

, , Kotlin 1.2 .

, Kotlin contract dsl, , ATM ( internal stdlib), , ( a stdlib, ).

stdlib:

@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)
}

, -

contract {
   when(null != default) implies (returnValue != null)
}

, .

default NotNull Long

val nullableLong = blabla
val result = nullableLong?.let { oraora.optLong(mudamuda, it) }

result Long?, null, nullableLong null.

+1

, .

fun <T: Long?> Map<String, String>.optLong(key: String, default: T): T 
{
    // do something.
    return default
}

:

fun main(args: Array<String>) {
    val nullable: Long? = 0L
    val notNullable: Long = 0L

    someMap.optLong(nullable) // Returns type `Long?`
    someMap.optLong(notNullable) // Returns type `Long`
}

, Long? Long. , , , .

" Kotlin, , null, ".

0

Source: https://habr.com/ru/post/1696153/


All Articles