Home > Net >  Issue with Kotlin Interface Delegation int toString/equals/hash functions
Issue with Kotlin Interface Delegation int toString/equals/hash functions

Time:03-15

Lets asume that we have following interface with a concrete class:

interface Foo {
    fun getString():String
}
class FooImpl : Foo {
    private val amber = "Hello Amber!"
    override fun getString(): String {
       return amber
    }
    override fun toString(): String {
        return amber
    }
}
class FooWrapper(foo: Foo): Foo by foo

then we run this with:

 val fooImpl = FooImpl()
 val fooWrap = FooWrapper(fooImpl)
 println("${fooImpl.toString()} vs ${fooWrap.toString()}")
 println("${fooImpl.getString()} vs ${fooWrap.getString()}")

and we get

Hello Amber! vs test.myapplication.FooWrapper@90db1fa
Hello Amber! vs Hello Amber!

Why .toString is also not delegated?

CodePudding user response:

Taken from Kotlin docs, where i changed the names according to your example:

The by-clause in the supertype list for FooWrapper indicates that foo will be stored internally in objects of FooWrapper and the compiler will generate all the methods of Foo that forward to foo.

Essentially meaning: "Everything declared in the interface gets forwarded". You did not declare toString (or the other methods) as part of the interface and thus no automatic forwarding will happen.

Add explicit references to resolve that issue:

interface Foo {
    fun getString():String
    override fun toString(): String
}

Notice that you will need to specify override.

CodePudding user response:

As the Kotlin document describes:

The by-clause in the supertype list for Foo indicates that foo will be stored internally in objects of FooWrapper and the compiler will generate all the methods of Foo that forward to foo.

It is the same as the java static proxy, in which we have to implement all interface methods, but in kotlin, the Delegation makes it good, we only need to override the method we want to modify or proxy, the other method will auto-generate for it. That makes our code simple and clear.

In the android studio, we can use the tool show kotlin bytecode, it will show the actual class.

public final class FooWrapper implements Foo {
   // $FF: synthetic field
   private final Foo $$delegate_0;

   public FooWrapper(@NotNull Foo foo) {
      Intrinsics.checkParameterIsNotNull(foo, "foo");
      super();
      this.$$delegate_0 = foo;
   }

   @NotNull
   public String getString() {
      return this.$$delegate_0.getString();
   }
}

As for the toString method, it belongs to the object, not Foo, so it is not delegated by foo. it called the default the parent object toString method.

//In the java Object
public String toString() {
        return getClass().getName()   "@"   Integer.toHexString(hashCode());
    }

So it prints the test.myapplication.FooWrapper@90db1fa

  • Related