How to use multi-generics in modules? - kotlin

In java, i hava code like below:
public class GenericTest {
private static final GenericTest instance = new GenericTest();
IRequirement requirement;
public static GenericTest getInstance() {
return instance;
}
public class ClassA {}
public interface InterfaceA {}
public void init(IRequirement requirement){
this.requirement = requirement;
}
public interface IRequirement {
<T extends ClassA & InterfaceA> T supply();
}
class ClassB {
void doSomeThing() {
ClassA a = requirement.supply();
InterfaceA ia = requirement.supply();
}
}
}
I can get ClassA or InterfaceA instance according to my needs.
But in kotlin, same codes like below:
open class ClassA(val name: String) {
fun function1() {}
fun function2() {}
}
interface InterfaceA {
fun iFunction1()
}
class ModuleX private constructor() {
var requirement: IRequirement? = null
companion object {
val instance = ModuleX()
}
fun init(requirement: IRequirement) {
instance.requirement = requirement
}
interface IRequirement {
fun <T> supply(): T where T : ClassA, T : InterfaceA
}
}
object ClassB {
inline fun <reified T> doSomeThing() where T : ClassA, T : InterfaceA{
val require = ModuleX.instance.requirement?.supply<T>()
require?.function1()
require?.iFunction1()
}
fun doAnotherThing() {
// IDE give an error when calling supply()
val require = ModuleX.instance.requirement?.supply()
require?.function1()
require?.iFunction1()
}
}
I must specify the actual type of the generic, or use the generic method, otherwise I will not be able to use the IRequirement in the code above, such as in ClassB.doAnotherThing() where IDE give an error "Type inference failed: Not enough information to infer parameter T in fun supply( ): T where T : InterfaceAPlease specify it explicitly."
My question is: In my module, it is required to provide a class that extends ClassA and implements InterfaceAd, but the module does not know the exact type of the class because it is outside the module. How should I use generics in this case?

fun doAnotherThing() {
val require: Any? = ModuleX.instance.requirement?.supply()
if (require != null) {
(require as ClassA).function1()
(require as InterfaceA).iFunction1()
}
}

Related

Kotlin generic type inference - inheritance

I have some abstract with generic type:
interface Abstract<T> {
val dataHolder: T
}
class AbstractImplA : Abstract<String> {
override val dataHolder = "Test"
}
class AbstractImplB : Abstract<Int> {
override val dataHolder = 1
}
Now I want to create open class that persist this data:
open class Base<T>(private val abstract: Abstract<T>) {
val data : T get() = abstract.dataHolder
// ...
}
now for child class I have to explicitly specifiy generic type of Abstract:
class ClassA : Base<String>(AbstractImplA()) {
fun foo() {
assertEquals("Test", data)
}
}
class ClassB : Base<Int>(AbstractImplB()) {
fun foo() {
assertEquals(1, data)
}
}
I wander if Kotlin can infere this type.
Passing wrong generic type causes Type mismatch error ex. class ClassB : Base<Boolean>(AbstractImplB())
Can I somehow write it like this?:
class ClassB : Base(AbstractImplB()) {
fun foo() {
assertEquals(1, data)
}
}

how to pass generic class implementing generic interface to another generic class Kotlin

Hi I am new to programming and trying to implement MVP pattern by passing generic Presenter class LoginPresenter to Generic Model Class LoginUserModel but getting type mismatch error.
on loginUserModel.onAttach(this)
and I am unable to figure out how to pass pass generic interface to another class.
Login Presenter
class LoginPresenter<V : ILoginView>: BasePresenter<V>(), ILoginPresenter<V> {
lateinit var loginUserModel: LoginUserModel<ILoginPresenter<ILoginView>>
lateinit var iLoginPresenter: ILoginPresenter<V>
.........
.........
override fun setupModel() {
iLoginPresenter = this
loginUserModel = LoginUserModel()
// here i am getting error
/**
Type mismatch.
Required:
ILoginPresenter<ILoginView>
Found:
LoginPresenter<V>
*/
loginUserModel.onAttach(this)
}
}
Login Model
class LoginUserModel<P: ILoginPresenter<ILoginView>> : LoginModelContract<P> {
var iLoginPresenter : P? = null
override fun onAttach(ILoginPresenter: P) {
iLoginPresenter = ILoginPresenter
}
}
LoginModelContract
public interface LoginModelContract<P: ILoginPresenter<ILoginView>> {
fun getUsersList(
userName:String,
guid: String
)
fun onAttach(ILoginPresenter: P)
fun onDetatch()
fun getPresenter(): P?
}
You can use two generic statements like below
class LoginUserModel<V: ILoginView, P : ILoginPresenter<V>> : LoginModelContract<V,P> {
var iLoginPresenter : P? = null
override fun onAttach(ILoginPresenter: P) {
iLoginPresenter = ILoginPresenter
}
}
interface ILoginView{
}
interface ILoginPresenter<T>{
fun setupModel()
}
class LoginPresenter<V : ILoginView>: ILoginPresenter<V> {
lateinit var loginUserModel: LoginUserModel<V,ILoginPresenter<V>>
lateinit var iLoginPresenter: ILoginPresenter<V>
override fun setupModel() {
iLoginPresenter = this
loginUserModel = LoginUserModel()
loginUserModel.onAttach(this)
}
}
public interface LoginModelContract<V: ILoginView, P : ILoginPresenter<V>> {
fun onAttach(ILoginPresenter: P)
}

How to get a reference to delegated instance in Kotlin using delegation 'by'?

Is there any way to get a reference to the delegated object in Kotlin?
Here's an example:
interface A {
fun test()
}
class B: A {
override fun test() {
println("test")
}
}
class C: A by B() {
override fun test() {
// ??? how to get a reference to B's test() method?
}
}
There's currently no way to do that directly. You can achieve that by storing it in a property declared in the primary constructor as follows:
class C private constructor(
private val bDelegate: B
) : A by bDelegate {
constructor() : this(B())
/* Use bDelegate */
}
Another workaround to hotkey's answer might be to include a delegate value
on the A interface...
interface A {
val delegate: A
fun test()
}
class B: A {
override val delegate get() = this
override fun test() {
println("test")
}
}
class C: A by B() {
override fun test() {
delegate.test()
}
}
... this is useful for when zero-arg constructors are required by a framework, e.g. Android Activities

Replacing SAM-constructor with lambda with covariant type

I have got the following Java interfaces:
interface Action1<T> {
void call(T t);
}
interface Test<T> {
void test(Action1<? super T> action)
}
And the following Kotlin class:
interface A {
fun go()
}
abstract class Main {
abstract fun a(): Test<out A>
fun main() {
a().test(Action1 { it.go() })
a().test { it.go() }
}
}
Now in the function main, the first statement compiles, but IntelliJ gives a warning that the SAM-constructor can be replaced with a lambda.
This would result in the second statement.
However, this second statement does not compile, because it has type Any?, not A. Removing the out modifier makes it compile again.
Why does this happen?
The use case of this is when the implementing class of Main needs to return Test<B> for the function a(), where B implements A:
class B : A {
override fun go() {
TODO()
}
}
class MainImp : Main() {
override fun a(): Test<out A> {
val value: Test<B> = object : Test<B> {
override fun test(action: Action1<in B>?) {
TODO()
}
};
return value
}
}
It is a compiler bug. You can track it here: https://youtrack.jetbrains.com/issue/KT-12238.

Kotlin outer scope

I would like to access the scope of the calling class when creating an "anonymous inner class"
in Kotlin. What would be the equivalent of Java's OuterScope.this syntax? example :
open class SomeClass {
open fun doSomething() {
// ...
}
}
class MyClass {
fun someFunc() {
object : SomeClass() {
override fun doSomething() {
super<SomeClass>.doSomething()
// Access the outer class context, in Java
// this would be MyClass.this
}
}
}
}
this#MyClass
JFYI:
the same syntax for access to receiver of extension function:
fun MyClass.foo() {
// in some nested thing:
this#foo
//...
}
Kotlin Reference: This expressions
in my case i accessed it like : this#MainActivity
class MainActivity : AppCompatActivity() {
inner class Anon : Observer<PagedList<ApplicationUsers>> {
override fun onChanged(pagedList: PagedList<ApplicationUsers>?) {
Toast.makeText(this#MainActivity, "hello", Toast.LENGTH_SHORT).show()
}
}
}