Kotlin override generic variable - kotlin

I have the following classes, but myfield variable in both NumberField and TextField cannot compile with:
Var-property type is InputField<String?>, which is not a type of overridden public abstract var inputField: InputField<*> defined in [my project]
interface FieldComponent {
var myfield: InputField<*> // <-- what should this be
}
interface InputField<T> {
fun collectInput(): T
}
class NumberField(): FieldComponent{
override lateinit var myfield: InputField<Int> // won't compile
fun doSomething(){
val x: Int = myfield.collectInput()
}
}
class TextField(): FieldComponent{
override lateinit var myfield: InputField<String> // won't compile
fun doSomething(){
val x: String = myfield.collectInput()
}
}
I don't really need to know about the type in FieldComponent, but I need to have access to myfield if I have an instance of FieldComponent
Can we make this work? Thank you

Make FieldComponent generic.
interface FieldComponent<T> {
var myfield: InputField<T>
}
interface InputField<T> {
fun collectInput(): T
}
class NumberField(): FieldComponent<Int> {
override lateinit var myfield: InputField<Int>
fun doSomething(){
val x: Int = myfield.collectInput()
}
}
class TextField(): FieldComponent<String> {
override lateinit var myfield: InputField<String>
fun doSomething(){
val x: String = myfield.collectInput()
}
}

Related

Kotlin encapsulating multiple 3rd party interfaces into one

Third party library library:
cannot be modified
service type library
interface I3rdParty1 {
fun fun1(): Int?
fun fun2()
//...
fun funA()
fun funB()
//...
}
interface I3rdParty2 {
fun fun1(): Int?
fun fun2()
//...
fun funX()
fun funY()
//...
}
class Service() {
fun getService1(): I3rdParty1
fun getService2(): I3rdParty2
}
Notes:
Both have the same common set of function signatures.
No function with the same name but different signature.
Only one of the service will be available and not both.
There are about 10 common ones and about 5 unique ones on both interfaces.
In my code the goal is to encapsulate both services and merge them into one or something. Without adding boilerplate code.
interface MyService extends I3rdParty1, I3rParty2 {
// Can I not write all 15 common ones and 2x5 uniques ones here?
}
class MyCode() : MyService {
var service1: I3rdParty1? = null
var service2: I3rdParty2? = null
fun detectService() {
service1 = Service().getService1()
service2 = Service().getService2()
}
// Is there a way to simplify this?
override fun1(): Int? {
return if (service1 != null)
service1.fun1()
else if (service2 != null)
service2.fun1()
else null
}
override fun2() {
if (service1 != null)
service1.fun2()
else if (service2 != null)
service2.fun2()
}
}
You can use a Delegation pattern.
interface I3rdParty1 {
fun fun1(): Int?
fun fun2()
//...
fun funA()
fun funB()
//...
}
interface I3rdParty2 {
fun fun1(): Int?
fun fun2()
//...
fun funX()
fun funY()
//...
}
class Service() {
fun getService1(): I3rdParty1
fun getService2(): I3rdParty2
}
interface MyService : I3rdParty1, I3rdParty2
class MyCode(private val service: Service) : MyService {
private val service1: I3rdParty1? = service.getService1()
private val service2: I3rdParty2? = service.getService2()
override fun fun1(): Int? = service1?.fun1() ?: service2?.fun1()
override fun fun2() = service1?.fun2() ?: service2?.fun2()
override fun funA() = service1?.funA() ?: service2?.funA()
override fun funB() = service1?.funB() ?: service2?.funB()
override fun funX() = service1?.funX() ?: service2?.funX()
override fun funY() = service1?.funY() ?: service2?.funY()
}
Explanation of ?::
service1?.fun1() ?: service2?.fun1()
is equivalent to
if (service1 != null) {
service1.fun1()
} else {
service2?.fun1()
}

When will the init{...} be launched in a Class of Kotlin?

I run Code A, and get the error Result A. It seems that isRecordingState has't been initialized.
So I modify Code A as Code B, and Code B can run correctly.
In my mind, I can place different functions in any order in a class of Kotlin.
I think init{ } of a Class will be launched after the object has been initialized, so I think I can place init{ } in any place of a class.
What's wrong with my ideas?
Code A
#HiltViewModel
class SoundViewModel #Inject constructor(
#ApplicationContext private val appContext: Context,
...
): ViewModel() {
init { beginSoundDensity() }
private val _timeXState = MutableStateFlow(0)
var isRecordingState by mutableStateOf(false)
private set
private var myJob: Job?=null
fun beginSoundDensity() {
if (isRecordingState == false) {
isRecordingState = true
myJob?.cancel()
...
}
}
}
Result A
java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object androidx.compose.runtime.State.getValue()' on a null object reference
at info.dodata.soundmeter.presentation.viewmodel.SoundViewModel.isRecordingState(SoundViewModel.kt:245)
at info.dodata.soundmeter.presentation.viewmodel.SoundViewModel.beginSoundDensity(SoundViewModel.kt:81)
at info.dodata.soundmeter.presentation.viewmodel.SoundViewModel.<init>(SoundViewModel.kt:39)
Code B
#HiltViewModel
class SoundViewModel #Inject constructor(
#ApplicationContext private val appContext: Context,
...
): ViewModel() {
private val _timeXState = MutableStateFlow(0)
var isRecordingState by mutableStateOf(false)
private set
private var myJob: Job?=null
init { beginSoundDensity() }
fun beginSoundDensity() {
if (isRecordingState == false) {
isRecordingState = true
myJob?.cancel()
...
}
}
}
The code just runs from top to bottom, so this code for example prints "12345"
fun main() {
A()
}
class A {
init {
print("1")
}
val s2 = printAndReturn("2")
init {
print("3")
}
val s4 = printAndReturn("4")
init {
print("5")
}
private fun printAndReturn(s: String): String {
print(s)
return s
}
}

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)
}

Is it possible to verify at compile time whether the required function is called for the Factory Class in Kotlin?

class ModelFactory {
fun setA() : ModelFactory {
// blabla...
}
fun setB() : ModelFactory {
// blabla...
}
fun setC() : ModelFactory {
// blabla...
}
fun build() : Model {
// An error occurs if any of setA, setB, and setC is not called.
}
}
//example
fun successTest() {
ModelFactory().setA().setB().setC().build() // No error occurs at compile time
}
fun failTest() {
ModelFactory().setA().build() // An error occurs at compile time because setB and setC are not called.
}
It's awkward grammatically, but I think it's been expressed what I want.
I have already implemented an error-raising runtime for this requirement, but I want to check this at compile time.
If possible, I think I should use annotations. But is this really possible at compile time?
With Kotlin, I have been avoiding builder pattern, as we can always specify default values for non-mandatory fields.
If you still want to use a builder pattern, you can use Step builder pattern that expects all mandatory fields to be set before creating the object. Note that each setter method returns the reference of next setter interface. You can have multiple Step builders based on the combination of mandatory fields.
class Model(val a: String = "", val b: String = "", val c: String = "")
class StepBuilder {
companion object {
fun builder(): AStep = Steps()
}
interface AStep {
fun setA(a: String): BStep
}
interface BStep {
fun setB(b: String): CStep
}
interface CStep {
fun setC(c: String): BuildStep
}
interface BuildStep {
//fun setOptionalField(x: String): BuildStep
fun build(): Model
}
class Steps : AStep, BStep, CStep, BuildStep {
private lateinit var a: String
private lateinit var b: String
private lateinit var c: String
override fun setA(a: String): BStep {
this.a = a
return this
}
override fun setB(b: String): CStep {
this.b = b
return this
}
override fun setC(c: String): BuildStep {
this.c = c
return this
}
override fun build() = Model(a, b , c)
}
}
fun main() {
// cannot build until you call all three setters
val model = StepBuilder.builder().setA("A").setB("B").setC("C").build()
}

MutableLiveData for collections

I request data from server by bunches and store it in the array.To track fetching of the next bunch of the data I have this class.In the addItems method I notify diffObservers and pass list of new items:
class PackItems:MutableLiveData<ArrayList<GetPacksResponse.PackData>>() {
private var diffObservers=ArrayList<Observer<List<GetPacksResponse.PackData>>>()
private var active=false
fun observeItems(owner: LifecycleOwner, valueObserver:Observer<List<GetPacksResponse.PackData>>,diffObserver:Observer<List<GetPacksResponse.PackData>>) {
super.observe(owner,valueObserver)
diffObservers.add(diffObserver)
}
override fun removeObservers(owner: LifecycleOwner) {
super.removeObservers(owner)
diffObservers= ArrayList()
}
fun addItems(toAdd:List<GetPacksResponse.PackData>) {
value?.addAll(toAdd)
if (active)
for (observer in diffObservers)
observer.onChanged(toAdd)
}
override fun onActive() {
super.onActive()
active=true
}
override fun onInactive() {
super.onInactive()
active=false
}
}
The problem is PackItems is MutableLiveData and it's not good practice to expose it.Is there way to cast it to LiveData?Like usually we do:
private val _items = MutableLiveData<List<Int>>()
val items: LiveData<List<Int>> = _items
UPD:Ideally would be if I could expose completely immutable LiveData.But I can't just write
private val _packs:PackItems=PackItems()
val packs:LiveData<ArrayList<GetPacksResponse.PackData>>
get()=_packs
Because in this case packs won't contain observeItems method.Therefore there must be custom class derived from LiveData like:
open class PackItems: LiveData<ArrayList<GetPacksResponse.PackData>>() {
protected var active=false
protected var diffObservers = ArrayList<Observer<List<GetPacksResponse.PackData>>>()
fun observeItems(owner: LifecycleOwner, valueObserver: Observer<List<GetPacksResponse.PackData>>, diffObserver: Observer<List<GetPacksResponse.PackData>>) {
super.observe(owner,valueObserver)
diffObservers.add(diffObserver)
}
//...
}
class MutablePackItems: PackItems() {
fun addItems(toAdd:List<GetPacksResponse.PackData>) {
value?.addAll(toAdd)
if (active)
for (observer in diffObservers)
observer.onChanged(toAdd)
}
}
But in this case I won't be able to set data because now MutablePackItems is LiveData(immutable) :)
I'd consider using composition instead of inheritance:
class PackItems() {
private val mutableData = MutableLiveData<ArrayList<GetPacksResponse.PackData>>()
val asLiveData: LiveData<ArrayList<GetPacksResponse.PackData>> get() = mutableData
...
fun observeItems(owner: LifecycleOwner, valueObserver:Observer<List<GetPacksResponse.PackData>>,diffObserver:Observer<List<GetPacksResponse.PackData>>) {
mutableData.observe(owner,valueObserver)
diffObservers.add(diffObserver)
}
fun removeObservers(owner: LifecycleOwner) {
mutableData.removeObservers(owner)
diffObservers = ArrayList()
}
// etc
}
EDIT: to set active as in your original code, may be a bit nastier:
private val mutableData = object : MutableLiveData<ArrayList<GetPacksResponse.PackData>>() {
override fun onActive() {
super.onActive()
active = true
}
override fun onInactive() {
super.onInactive()
active = false
}
}
EDIT 2:
but the main problem is I need to return custom LiveData class with custom observeItems method
The point is that you don't necessarily. Whenever you'd call LiveData's method (e.g. observe), just call items.asLiveData.observe(...) instead. If you want to pass it to another method foo accepting LiveData, call foo(items.asLiveData).
In principle, you could modify this approach by extending LiveData and delegating all calls to mutableData:
class PackItems(): LiveData<ArrayList<GetPacksResponse.PackData>>() {
private val mutableData = MutableLiveData<ArrayList<GetPacksResponse.PackData>>()
...
fun observeItems(owner: LifecycleOwner, valueObserver:Observer<List<GetPacksResponse.PackData>>,diffObserver:Observer<List<GetPacksResponse.PackData>>) {
mutableData.observe(owner,valueObserver)
diffObservers.add(diffObserver)
}
override fun observe(owner: LifecycleOwner, observer: ArrayList<GetPacksResponse.PackData>) {
mutableData.observe(owner, observer)
}
override fun removeObservers(owner: LifecycleOwner) {
mutableData.removeObservers(owner) // not super!
diffObservers = ArrayList()
}
// etc
}
but I don't think it's a good idea.