Kotlin null safety with generic types

Hi, I am new to Kotlin, but familiar with Scala. I’ve been going though kotlinlang documentation.
I came up to the point about generics where it says

The default upper bound (if none specified) is Any?

Does this mean I cannot rely on compiler for null safety on B in the case of A<B>?

example


class Down<T>(val x:T)

fun <String> jump(x : Down<String>):Down<String> {
  println("Jumped")
  return x
}

val jump = jump(Down(null))
println(jump)
println(jump.x) - null

Would I have to change fun <String> jump to fun <String:Any> jump?
I mean yes that would do it but is this the correct way to approach this?

1 Like

Yes, if you have a parameterized type declared as MyClass<T> then T could be nullable. And if you need to work with not null values only, then you need to declare it as: MyClass<T : Any>.

I’m not sure, why do you say that you can’t rely on the compiler for null-safety here. If you allowed null values then you need to handle them :slight_smile:

Also, your example is very misleading and I’m not sure if you did this intentionally or not. I just want to make sure that you are aware that your jump() function isn’t at all related to strings and it could receive any Down instance? x could be nullable, it could be an integer, etc.

1 Like

It seems a bit confusing that return type says Down<String>. Yet I can still have a null reference Down.x. I would somehow expect to be forced to say Down<String?> :slight_smile: . Or otherwise not be allowed a x <-null

I mean similarly to how you treat non-generics eg Animal vs Animal? ? Maybe my lack of understanding some key concepts here?

Ok, so I guess your example wasn’t intentional, but it was a mistake :wink:

By doing this: fun <String> you declared a parameter type String, overriding class String. This function has nothing to do with strings. It is an equivalent of:

fun <T> jump(x : Down<T>):Down<T>

So it can receive and return any Down objects, including ones where T is nullable. If you want your jump() function to work only with strings and only non-nullable, then just remove <String>. You will notice that you are no longer able to pass Down(null) to it and you can be sure that x is not null.

Ah yes. That was my mistake. I actually started from fun <T> jump(x : Down<T>):Down<T>, but I forgot to carry the 1 and ended up in a totally different place :smiley:

Thanks!

1 Like