0

I have question about generic types, subtypes and mismatching between those. I have specific structure classes and interface. I'll show you and please explain me why the type mismatch occurs.

Let's say I'm preparing my MVP framework and I have following interfaces and classes:

This is highest abstraction

interface Presenter<in V : AbstractView> {
    fun attachView(view: V)

    fun detachView()

    fun onDestory() {

    }
}

The abstract class contains specific methods and implementation of Presenter

abstract class AbstractPresenter<V : AbstractView> : Presenter<V>, LifecycleObserver {

    private var viewReference: WeakReference<V?>? = null

    protected abstract fun onAttached(view: V)

    final override fun attachView(view: V) {
        viewReference = WeakReference(view)
        onAttached(view)
    }

    final override fun detachView() {
        viewReference?.clear()
        viewReference = null
        onDetached()
    }

    protected open fun onDetached() {
    }
}

Contract

interface DashboardContract {

    interface View : AbstractView {

    }

    abstract class Presenter : AbstractPresenter<View>(){

    }
}

and finally

class DashboardPresenter : DashboardContract.Presenter() {

    override fun onAttached(view: DashboardContract.View) {
    }
}

In terms of AbstractView it looks simpler. There is just interface AbstractView. In contract DashboardContract.View extends AbstractView interface and my DashboardActivity implement this DashboardContract.View interface.

class DashboardActivity : BaseActivity(), DashboardContract.View { ... }

So when I create DashboardPresenter as a property in my DashboardActivity and create method fun getPresenter() : Presenter<AbstractView> then I got Type mismatch error Why? isn't a subtype of Presenter<AbstractView>?

fun getPresenter() : AbstractPresenter<AbstractView> {
        return dashboardPresenter // The type is DashboardPresenter
    }

Let's take a looka at the Java code:

I'm watching the Java code from decompile Kotlin. I put it below. This is how the Presenter looks like:

public interface Presenter {
   void attachView(@NotNull AbstractView var1);

   void detachView();

   void onDestory();

   @Metadata(...)
   public static final class DefaultImpls {
      public static void onDestory(Presenter $this) {
      }
   }
}

I thought that If I use generic class in Kotlin I get the generic class in java too. I was wrong.

The AbstractPresenter gives:

public abstract class AbstractPresenter implements Presenter, LifecycleObserver {
   private WeakReference viewReference;

   protected abstract void onAttached(@NotNull AbstractView var1);

   public final void attachView(@NotNull AbstractView view) {
      Intrinsics.checkParameterIsNotNull(view, "view");
      this.viewReference = new WeakReference(view);
      this.onAttached(view);
   }

   public final void detachView() {
      WeakReference var10000 = this.viewReference;
      if(this.viewReference != null) {
         var10000.clear();
      }

      this.viewReference = (WeakReference)null;
      this.onDetached();
   }

   protected void onDetached() {
   }

   public void onDestory() {
      DefaultImpls.onDestory(this);
   }
}

Contract

public interface DashboardContract {
   @Metadata(...)
   public interface View extends AbstractView {
   }

   @Metadata(...)
   public abstract static class Presenter extends AbstractPresenter {
   }
}

The DashboardPresetner:

public final class DashboardPresenter extends Presenter {

   protected void onAttached(@NotNull View view) {
      Intrinsics.checkParameterIsNotNull(view, "view");
   }

   // $FF: synthetic method
   // $FF: bridge method
   public void onAttached(AbstractView var1) {
      this.onAttached((View)var1);
   }
}
Michael
  • 780
  • 1
  • 10
  • 34

1 Answers1

0

You have to change the parent of Presenter in DashboardContractto use AbstractView instead of View:

abstract class Presenter : AbstractPresenter<AbstractView>()

I'm not sure why you're not allowed to use View instead, this might be a flaw in the recursive type checking of Kotlin. It might be interesting to see what the corresponding java code is and continue investigating from that.

Anton
  • 1,314
  • 1
  • 12
  • 27
  • Thank you for your answer and I'm sorry for delay. I'm still investigation. I'm not sure what you mean parent of `Presenter` - `Presenter` is highest abstraction. I'm take a look at the corresponding java code and I'll put it on the question. – Michael Mar 16 '18 at 22:19
  • Ah yes, I meant the `Presenter` class inside `DashboardContract`. – Anton Mar 17 '18 at 09:48
  • Yes it works. But right now I have to manually cast `AbstractView` to `DashboardContract.View`, because `DashboardPresenter` class keeps the `AbstractionView` instead of `DashboardContract.View`. I added also Java code in my question. – Michael Mar 17 '18 at 17:23