I'm getting Overload resolution ambiguity error on kotlin safe call

后端 未结 5 2173
眼角桃花
眼角桃花 2021-02-20 01:27

I have a nullable string variable ab. If I call toUpperCase via safe call operator after I assign null to it, kotlin gives error.

fun m         


        
相关标签:
5条回答
  • 2021-02-20 01:53

    I believe this is due to smart casts used by Kotlin. In other words, Kotlin is able to infer that after this line of code:

    ab = null
    

    type of variable ab is simply null (this is not actual type you can use in Kotlin - I am simply referring to range of allowed values), not String? (in other words, there is no way ab might contain a String).

    Considering that toUpperString() extension function is defined only for Char and String (and not Char? or String?), there is no way to choose between them.

    To avoid this behaviour see answers proposed by other guys (e.g. explicit casting to String?), but this definitely looks like a feature (and quite a useful one) rather than a bug for me.

    0 讨论(0)
  • 2021-02-20 01:55

    It really seems like a bug. The type String? is lost somehow upon assigning null, so you have to tell the compiler explicitely that it should deal with a String?.

    fun main(args: Array<String>){
        var ab: String? = "hello"
        ab = null
        println((ab as String?)?.toUpperCase()) // explicit cast
    
        // ...or
    
        println(ab?.let { it.toUpperCase() }) // use let
    }
    
    0 讨论(0)
  • 2021-02-20 01:59

    I decompiled your function and I figured: after the moment you make ab = null the compiler will smartcast it, putting null (ACONST_NULL) in every ocurrence of ab. Then as null has no type. you can't infer the type for the receiver of toUpperCase().

    This is the java equivalent code generated from the kotlin byte code:

    public final void main(@NotNull String[] args) {
       Intrinsics.checkParameterIsNotNull(args, "args");
       String ab = "hello";
       ab = (String)null;
       Object var3 = null;
       System.out.println(var3);
    }
    

    It looks as an issue that should be resolved by the kotlin team.

    0 讨论(0)
  • 2021-02-20 02:06

    I'm not sure but that seems to be a bug due to smart casting (to Nothing?, subtype of every nullable type). This one works:

    fun main(args: Array<String>) {
        var ab: String? = "hello"
        ab = makeNull()
        println(ab?.toUpperCase())
    }
    
    fun makeNull(): String? = null
    

    The only difference: The compiler does not know the null assignment directly, which seems to cause the error in your example. But still, yours should probably work too.

    0 讨论(0)
  • 2021-02-20 02:15

    As stated in this doc about smart-casts:

    x = y makes x of the type of y after the assignment

    The line ab = null probably smart casts ab to Nothing?. If you check ab is Nothing? it is indeed true.

    var ab: String? = "hello"
    ab = null
    println(ab?.toUpperCase())
    println(ab is Nothing?) // true
    

    Since Nothing? is subtype of all types (including Char? and String?), it explains why you get the Overload resolution ambiguity error. The solution for this error will be what Willi Mentzel mentioned in his answer, casting ab to the type of String before calling toUpperCase().


    Remarks: This kind of error will occur when a class implements two interfaces and both interface have extension function of the same signature:

    //interface
    interface A {}
    interface B {}
    
    //extension function
    fun A.x() = 0
    fun B.x() = 0
    
    //implementing class
    class C : A, B {}
    
    C().x()    //Overload resolution ambiguity
    (C() as A).x()    //OK. Call A.x()
    (C() as B).x()    //OK. Call B.x()
    
    0 讨论(0)
提交回复
热议问题