Home > Net >  Kotlin inner class can't resolve extension function declared in outer class
Kotlin inner class can't resolve extension function declared in outer class

Time:10-12

Why inner class in Kotlin can't not access extension function declared in outer class as below:

class A{
    val a = "as".foo()      // LINE 1
    class B{
        val b = "as".foo()  // LINE 2
    }

    fun String.foo(){}
}

On LINE 1 extension function is resolved but on LINE 2 the function is not resolved. Wonder why there is such limitation?

CodePudding user response:

This is not an inner class, because you didn't use the keyword inner on it. It is merely a nested class. If you're familiar with Java, it's like a static inner class. Since it is not inner, it does not have any implicit reference to the outer class, and cannot make bare calls to members of the outer class since there is no specific instance to use the members of. It can however call members of the outer class on an instance of the outer class, so you could for example do the following:

class A{
    val a = "as".foo()
    class B{
        val b = A().run { "as".foo() }
    }

    fun String.foo(){}
}

Even though foo is an extension function, it's also a member of A because of where it's declared. Using a scope function that causes a class to be a receiver inside the scope is one way to call one of its member extension functions from another class.

EDIT: Here's an example of one reason you'd want to declare an extension inside a class.

class Sample(val id: Int) {
    private val tag = "Sample#$id"
    fun String.alsoLogged(): String{
        Log.d(tag, this)
        return this
    }
}

You can use this extension to easily log Strings you're working with inside the class (or when it's the receiver of run or apply). It wouldn't make sense to declare outside the class because it uses the private tag property of that class.

CodePudding user response:

It's because Kotlin compiles your code to

public final class A {
  @NotNull
  private final Unit a;

  @NotNull
  public final Unit getA() {
    return this.a;
  }

  public final void foo(@NotNull String $this$foo) {
    Intrinsics.checkNotNullParameter($this$foo, "$this$foo");
  }

  public A() {
    this.foo("as");
    this.a = Unit.INSTANCE;
  }
  
  public static final class B {
    public B() {
      // You can't access A's foo() method here.
    }
  }
}
  • Related