How am I supposed to get rid of the null-ability of function value?

class NonNullValuesMap<K, V>(private val map: MutableMap<K, V>, private val defaultCalculator: ((K) -> V)? = null)
    : MutableMap<K, V> by map {
    override operator fun get(key: K): V {
        val existing = map[key]
        if (existing != null)
            return existing
        
        if (defaultCalculator == null)
            return null!!
        
        val generated = defaultCalculator!!(key) //<< error here: Expression 'defaultCalculator!!' of type Nothing can not be invoked as a function 
        map[key] = generated
        return generated!!
    }
}

How am I supposed to get rid of the null-ability of val defaultCalculator ?

1 Like
val d = defaultCalculator ?: throw Error()
val generated = d(key)
1 Like

There are a few problems with your code, where I don’t understand why you chose to do it this way.
First

if(defaultCalculator == null)
     return null!!

looking at documentation of !! you see that it throws an exception if the value is null so this code is the same as

if(defaultCalculator == null) throw NullPointerException()

If this is what you want than throw an exception. Don’t use !!.

__

That said I can’t reproduce your compiler error. Your code works fine for me. Normally I would say you can change defaultCalculator!!(key) to defaultCalculator(key) since you did the null check above, but there seems to be a bug in kotlin with generics(https://youtrack.jetbrains.com/issue/KT-29911) so you have to keep the !! for now.

Thanks for all the notes.
It works for me with compiled kotlin too, but it was not (and still isn’t) working within a kotlin scratch file.

Now that you pointed it out - I find null!! a delightful shortcut to throw NullPointerException() :wink:

1 Like

The intention behind expr!! is (or should be)…

I assume that expr is never null. If it is, it means that an internal assumption was broken. The code should crash, but I don’t even blame the caller.

In the Java ecosystem, NullPointerException is sometimes used to say…

The precondition of this method was broken (as a parameter expected to be non-null is null). I blame the caller.

If you want (or are forced to) follow this convention in Kotlin, you should use an explicit throw combined with an if, or ?: (elvis) if applicable.

In this specific class, the intention is actually… I don’t know what’s the intention. Why is defaultCalculator a nullable type in the first place? What are the scenarios where it’s reasonable to instantiate NonNullValuesMap without defaultCalculator?

1 Like