Closed ValdZX closed 4 years ago
Hi @ValdZX! Thank you for submitting this issue, it definitely needs to be addressed. We discussed it with @asitnkova and found that the underlying question is even more fundamental:
Given any interface inheritance hierarchy for a View interface, how should the compiler resolve the resulting strategies for all its methods, both enclosed and inherited?
There are many edge cases, like methods with no strategies, clashing methods with different strategies, overridden methods with different strategies and so on. So before accepting any pull requests fixing the issue, we first need to specify the desired behavior for all these cases. We'll create a Wiki page with the spec, and we can discuss it in this issue.
Please do share your thoughts on this matter, as well as any other edge cases that come to mind.
Here is a list of cases that came to my mind. I'll provide code samples later, we can use them for tests.
MyView extends MvpView, ViewA
, ViewA
does not extend 'MvpView'.MyView extends ViewA
, ViewA extends MvpView
.MyView extends MvpView, ViewA
, ViewA extends MvpView
Suggested behavior: should work the same in all cases
Question: do we even need MvpView
at all?
MyView extends ViewA, ViewB
, both ViewA
and ViewB
have the same methods with different strategies.
Suggested behavior: compilation fails with an error.MyView extends ViewA
, both MyView
and ViewA
have the same methods with different strategies. Variant: one of the methods does not have a strategy at all.
Suggested behavior: the most "bottom" method in a hierarchy wins, if it has a strategy. If it doesn't have a strategy, compilation fails. MyView extends ViewA
, ViewA
has a method with a strategy that is not overridden in MyView
.
Suggested behavior: method from ViewA
is inherited with its strategy, and used to generate the resulting ViewState.@asitnkova @xanderblinov @ValdZX any other suggestions?
MvpView
is just a marker interface. I think it's a good idea to explicitly define, what interfaces are view interfaces. And there's no need for an explicit check because MvpPresenter
's type parameter is bound by MvpView
.
Regarding strategy conflict, I think we need to specify these two points:
I think, if the method overrides superinterface's method, then all strategy info from the superinterface should be discarded. And if the same methods with different strategies exist in two superinterfaces, than compilation should fail, and the user has to override this method and specify strategy manually.
Right now methods are validated right as they parsed, which causes the reported bug. So we should move validation to the end of processing after all superinterfaces are processed.
There are some snippets showing the described behavior:
MyView
overrides someMethod()
interface ViewA {
@OneExecution fun someMethod()
}
interface MyView : ViewA {
@AddToEnd override fun someMethod()
}
class ViewState: MyView {
override fun someMethod() // AddToEnd
}
No override
interface ViewA {
@OneExecution fun someMethod()
}
interface MyView : ViewA
class ViewState : MyView {
override fun someMethod() // OneExecution
}
ViewA
defines no strategies, MyView
overrides someMethod()
, strategy placed on interface
interface ViewA {
fun someMethod()
}
@AddToEnd
interface MyView : ViewA {
override fun someMethod()
}
class ViewState : MyView {
override fun someMethod() // AddToEnd
}
Speaking of implementation, current ViewMethod
class could be replaced with two classes:
ViewMethod
- intermediate class, that represents method as declared in view interface, and has a nullable strategy.ViewStateMethod
- represents a method to be generated in ViewState, and has a non-null strategy.After all of the superinterfaces are processed, ViewMethod
s will be converted to ViewStateMethod
s, reporting on missing strategies if any.
Sample: