Type Inference Query

class Main{
   
    fun sayName(name:String?){
        println("This is your name:$name again")
    }

    fun sayName(name:String){
        println("This is your name:$name")
    }

}

fun main() {
    val main= Main()

    main.sayName("Brymher 2")
}

From the provided code sayName(name:String) is called. And there is no conflict in the compiler interms of type? I’m not sure of this behaviour and why it’s allowed. Looks confusing when calling as then sayName(name:string?) can never be called with a string provided? i.e sayName("Brymher 1")

If you’re compiling to this to Kotlin/JVM, you’ll get a compiler warning:

 Platform declaration clash: The following declarations have the same JVM signature (sayName(Ljava/lang/String;)V):

Kotlin as a language does not care though, it can differentiate between String? and String.

sayName(name:string?) can never be called with a string provided

if you mean a non-null value, then you still can, the compiler just can’t know it’s a non-null value.

private fun main() {
    val main= Main()

    val text: String? = "Brymher 2"
    main.sayName(text)
}
2 Likes

Just for completeness, if you forget about the limitations of the JVM (and the fact it cannot distinguish nullable from non-nullable), the situation in pure Kotlin should be as surprising (or not) as using overloads with super/subtypes:

fun main() {
    sayName("Bob")
    sayName("Bob" as CharSequence)
    sayName("Bob" as Any)
}

fun sayName(name: Any) = println("Hi Any $name")
fun sayName(name: CharSequence) = println("Hi CharSequence $name")
fun sayName(name: String) = println("Hi String $name")

String? just happens to be a supertype of String that can accept String values AND null.

https://pl.kotl.in/TCdtn6IY5

You can use any overload as long as the static type of the expression you pass is the correct one (or rather the closest one).

1 Like

Adding to the other good answers here, note that if you’re following basic best practises, this choice on Kotlin’s part is not likely to cause you any real trouble either. If you publish an overloaded method that only differs on the nullibility of the given type, then you almost certainly should make all impls of that method behave in a ‘not surprising’ way. For example:

fun sayName(name: String) = "Hello, $name"
fun sayName(name: String?) = name?.let(::sayName)

The nullable variant handles null, but otherwise just refers back to the nonnullable variant.

In practise your code will almost always work something like this, so you wouldn’t actually care too much which method got called.

1 Like