Out-projected type ... prohibits the use of 'public open fun .... defined in FooTable - kotlin

I have the following class:
abstract class FooTable<M, D> where M : IModel, D : IDto {
///...
fun getTableData(models: ArrayList<M>): ArrayList<D> {
// ...
}
}
And I have another class using it like:
abstract class FooPage<M, F> where M : IModel, F : IFilter {
abstract val table: FooTable<M, out IDto>
Then somewhere in my code I'm trying to do:
page.table.getTableData(arrayListOf(m1, m2)).first()
And it is giving me:
Out-projected type FooTable<out IModel, out IDto> prohibits the use of public final fun getTableData(models: kotlin.collections.ArrayList<M> /* = java.util.ArrayList<M> */): kotlin.collections.ArrayList<D> /* = java.util.ArrayList<D> */ defined in com.menighin.example.models.FooTable
Here is a fiddle with the problem: https://pl.kotl.in/ryirJJH9m
The code is:
interface IModel
interface IDto
interface IFilter
class Model : IModel
class Dto : IDto
class Filter : IFilter
class FooTable<M, D> where M : IModel, D : IDto {
fun getTableData(models: List<M>): ArrayList<D> {
return ArrayList()
}
fun testPage(masterModel: IModel, thisPage: FooPage<out IModel, out IFilter>) {
thisPage.table.getTableData(arrayListOf(masterModel)) // Error here
}
fun testTable(masterModel: IModel, masterTable: FooTable<out IModel, out IDto>) {
masterTable.getTableData(arrayListOf(masterModel)) // And error here
}
}
class FooPage<M, F> where M : IModel, F : IFilter {
val table: FooTable<M, out IDto> = FooTable()
}
fun main() {
val page = FooPage<Model, Filter>()
val a = page.table.getTableData(arrayListOf())
println("Hello, world!!!")
}
Basically there is a function in my FooTable in which I need to get reference for another Table and get its data. I guess I could pass in the data already but I'm curiou why this isn't working now...
I understand from this question that if I could change abstract val table: FooTable<M, out IDto> to abstract val table: FooTable<M, Any> it would be ok... But, as far as I know, I can't because the definition of FooTable is strict about the second parameter implementing IDto.
How can I fix this?

The problem is that in your testTable function you specify that masterTable's first generic type restriction (IModel) is out. If you change the declaration to this it compiles:
fun testTable(masterModel: IModel, masterTable: FooTable<in IModel, out IDto>)
(Alternatively, specify neither in nor out.)
This is explained here (though does take a bit getting your head round). I think that your existing code (with the IModel generic type restriction of out) states that the masterTable argument produces IModels, but there's no rules about what it takes in. Therefore the error (at least in IntelliJ) is:
Type mismatch. Required List<Nothing>. Found List<IModel>.
Because the compiler doesn't know what masterTable can take in, it can't be sure that it could take in the IModel you're trying to pass into the getTableData method.

Related

How to reference parameterized constructor in Kotlin?

So I have this definition:
sealed interface ParseResult<out R> {
data class Success<R>(val value: R) : ParseResult<R>
data class Failure(val original: String, val error: Throwable) : ParseResult<Nothing>
}
I want to wrap certain elements in a Success. And I know I can do it like this...
list.map{ParseResult.Success(it)}
But is there a way to use a constructor reference?
list.map(ParseResult::Success) //this won't compile
You can use a constructor reference if you add an import:
import somepackage.ParseResult.Success
Or even a typealias:
typealias Success<R> = ParseResult.Success<R>
Then you can do:
list.map(::Success)
The idea here is to make ParseResult.Success referrable by a simple name.
Not being able to do ParseResult::Success does look like a bug to me though. Compare:
class Outer {
class Nested
}
class OuterGeneric<T> {
class Nested
}
fun main() {
val x = Outer::Nested // works
val y = OuterGeneric::Nested // error
}

Type mismatch using generics

I have issues understanding generics and i failed to find the answer here.
Here is the issue:
I have an abstract class that is suppose to be the parent class to few viewmodels. Idea is, one view is going to be created based on data coming from different viewmodels.
And i want to draw it based on the same method, just using different Types.
Also, I dont want a return type, i want to trigger some callbacks.
Here is the abstract:
package foo.bar.ui.app.user_profile.view_model
abstract class UserDefaultsGenericViewModel : BaseViewModel() {
abstract fun <P> getData(
data: (P) -> Unit,
error: (Result.Error) -> Unit
)
}
And then example of one ViewModel is like this:
package foo.bar.ui.app.user_profile.view_model
#HiltViewModel
class StopViewModel #Inject constructor(
private val getStopsByRouteUseCase: ParamsUseCase<RouteParams, Stops>
) : UserDefaultsGenericViewModel() {
var stopId = ""
override fun <Stops> getData(data: (Stops) -> Unit, error: (Result.Error) -> Unit) {
viewModelScope.launch {
when (val resultStops = getStopsByRouteUseCase.invoke(RouteParams(stopId, Direction.ToWork))) {
is Result.Success -> {
data.invoke(resultStops.value)
}
is Result.Error -> Log.e("TAG", "bar")
}
}
}
}
The problem is in this line:
data.invoke(resultStops.value)
Im getting:
Type mismatch: inferred type is foo.bar.onboarding.Stops but Stops#1 (type parameter of foo.bar.ui.app.user_profile.view_model.StopViewModel.getData) was expected
What am i doing wrong?
You're using a generic method, but it looks like you want a generic class/interface.
In your override fun <Stops> getData, Stops is an arbitrary name of a type parameter, not the actual Stops type that you seem to want. What you probably want instead is the following:
// note the <P> at the class level
abstract class UserDefaultsGenericViewModel<P> : BaseViewModel() {
// no <P> here after the fun keyword
abstract fun getData(
data: (P) -> Unit,
error: (Result.Error) -> Unit
)
}
#HiltViewModel
class StopViewModel #Inject constructor(
private val getStopsByRouteUseCase: ParamsUseCase<RouteParams, Stops>
) : UserDefaultsGenericViewModel<Stops>() { // note the <Stops> type argument here
...
}
Here the <P> is on the class declaration, so that <P> is determined once for each instance of the class. If you declare the generic on the method, the actual type can be different for each method invocation.

Type inference of class type parameter in abstract method

// Bars.kt
abstract class Bar
class BarToo(/* fields */) : Bar()
// Foos.kt
abstract class Foo<T : Bar> {
abstract fun foo(bar: T)
}
class FooToo : Foo<BarToo>() {
override fun foo(bar: BarToo) { /* */ }
}
// FoosBars.kt
private val foos = HashMap<String, Foo<out Bar>>()
fun <T : Foo<out Bar>> putFoo(name: String, foo: T) {
foos.putIfAbsent(name, foo)
}
fun doFoo(name: String, bar: Bar) {
val foo = foos[name] ?: return
// Error: Type mismatch: inferred type is Bar but Nothing was expected
// https://pl.kotl.in/TSp3eO_Tj
foo.foo(bar)
}
If I manually specify the bounds of T at the method's declaration, the error in doFoo is resolved, e.g.:
abstract class Foo /* ... */ {
abstract <T : Bar> fun foo(bar: T)
}
but obviously prevents the subclasses from using the type parameter from the class declaration.
Is this type of hierarchy possible in Kotlin, or should I better explain what I am trying to accomplish in order to avoid an XY problem?
Thanks!
You need to use in instead of out. This allows child classes to be used as follows:
foo.foo(bar)
foo.foo(BarToo()) // no compile error
Ref: this

Kotlin generics with in produces Type mismatch when compiling

I´m working on a code with generics and when I use an in I got a TypeMismatch when compiling.
The code is the following:
open class A
class B:A()
data class DataContainer(val a:String,
val b:A)
interface Repo<T:A>{
fun setParam(param:T)
fun getParam():T
}
abstract class RepoImp<T:A>:Repo<T>{
private lateinit var parameter:T
override fun setParam(param: T) {
parameter = param
}
override fun getParam(): T {
return parameter
}
}
class BRepo:RepoImp<B>()
class Repo2(val repo: Repo<in A>){
fun process(b:DataContainer){
repo.setParam(b.b)
}
}
val repoB = BRepo()
val repo2 = Repo2(repoB)// Here I got: Type mismatch: inferred type is BRepo but Repo<in A> was expected
I also tried changing the attribute repo from Repo2 to Repo<*>
Since BRepo is a Repo<B>, it is not a Repo<in A>, (but it would satisfy Repo<out A>).
In other words, a Repo<in A> must be able to accept setParam(A()), but BRepo.setParam() can only accept a B or subclass of B.
Or to put it another way, BRepo is a Repo<B>, which is a tighter restriction on the type than Repo<A> when it comes to writing values (but looser restriction when reading values).
The reason class Repo2(val repo: Repo<*>) doesn't work is that Repo<*> is essentially a Repo<in Nothing/out A>. You can't call setParam() on a Repo<*> with any kind of object.
There's a design flaw in your code that you can't fix simply by changing Repo2's constructor signature. As it stands now, Repo2 needs to be able write A's to the object you pass to it, and a BRepo by definition does not support writing A's, only B's. You will need to make at least one of your class's definitions more flexible about types.
It might be easier to understand the covariance limitation with more common classes:
val stringList: MutableList<String> = ArrayList()
var anyList: MutableList<in Any> = ArrayList()
anyList.add(5) // ok
anyList = stringList // Compiler error.
// You wouldn't be able to call add(5) on an ArrayList<String>
Basically MutableList<String> is not a MutableList<in Any> the same way Repo<B> is not a Repo<in A>.
The Repo2 class expect to consume only type A, use Repo2<T : A>(val repo: Repo<in T>)
open class A
class B : A()
class C : A()
class D : A()
class BRepo : RepoImp<B>()
class CRepo : RepoImp<C>()
class DRepo : RepoImp<D>()
interface Repo<T : A> {
fun setParam(param: T)
fun getParam(): T
}
abstract class RepoImp<T : A> : Repo<T> {
private lateinit var parameter: T
override fun setParam(param: T) {
parameter = param
}
override fun getParam(): T {
return parameter
}
}
class Repo2<T : A>(val repo: Repo<in T>) {
fun process(b: DataContainer<T>) {
repo.setParam(b.b)
}
}
data class DataContainer<T : A>(
val a: String,
val b: T
)
fun main() {
val repoB = BRepo()
val repoC = CRepo()
val repoD = DRepo()
val repo2 = Repo2(repoB)
val repo3 = Repo2(repoC)
val repo4 = Repo2(repoD)
repo2.process(DataContainer("Process B type", B()))
repo3.process(DataContainer("Process C type", C()))
repo4.process(DataContainer("Process D type", D()))
println(repo2.repo.getParam())
println(repo3.repo.getParam())
println(repo4.repo.getParam())
}

How to specify "own type" as return type in Kotlin

Is there a way to specify the return type of a function to be the type of the called object?
e.g.
trait Foo {
fun bar(): <??> /* what to put here? */ {
return this
}
}
class FooClassA : Foo {
fun a() {}
}
class FooClassB : Foo {
fun b() {}
}
// this is the desired effect:
val a = FooClassA().bar() // should be of type FooClassA
a.a() // so this would work
val b = FooClassB().bar() // should be of type FooClassB
b.b() // so this would work
In effect, this would be roughly equivalent to instancetype in Objective-C or Self in Swift.
There's no language feature supporting this, but you can always use recursive generics (which is the pattern many libraries use):
// Define a recursive generic parameter Me
trait Foo<Me: Foo<Me>> {
fun bar(): Me {
// Here we have to cast, because the compiler does not know that Me is the same as this class
return this as Me
}
}
// In subclasses, pass itself to the superclass as an argument:
class FooClassA : Foo<FooClassA> {
fun a() {}
}
class FooClassB : Foo<FooClassB> {
fun b() {}
}
You can return something's own type with extension functions.
interface ExampleInterface
// Everything that implements ExampleInterface will have this method.
fun <T : ExampleInterface> T.doSomething(): T {
return this
}
class ClassA : ExampleInterface {
fun classASpecificMethod() {}
}
class ClassB : ExampleInterface {
fun classBSpecificMethod() {}
}
fun example() {
// doSomething() returns ClassA!
ClassA().doSomething().classASpecificMethod()
// doSomething() returns ClassB!
ClassB().doSomething().classBSpecificMethod()
}
You can use an extension method to achieve the "returns same type" effect. Here's a quick example that shows a base type with multiple type parameters and an extension method that takes a function which operates on an instance of said type:
public abstract class BuilderBase<A, B> {}
public fun <B : BuilderBase<*, *>> B.doIt(): B {
// Do something
return this
}
public class MyBuilder : BuilderBase<Int,String>() {}
public fun demo() {
val b : MyBuilder = MyBuilder().doIt()
}
Since extension methods are resolved statically (at least as of M12), you may need to have the extension delegate the actual implementation to its this should you need type-specific behaviors.
Recursive Type Bound
The pattern you have shown in the question is known as recursive type bound in the JVM world. A recursive type is one that includes a function that uses that type itself as a type for its parameter or its return value. In your example, you are using the same type for the return value by saying return this.
Example
Let's understand this with a simple and real example. We'll replace trait from your example with interface because trait is now deprecated in Kotlin. In this example, the interface VitaminSource returns different implementations of the sources of different vitamins.
In the following interface, you can see that its type parameter has itself as an upper bound. This is why it's known as recursive type bound:
VitaminSource.kt
interface VitaminSource<T: VitaminSource<T>> {
fun getSource(): T {
#Suppress("UNCHECKED_CAST")
return this as T
}
}
We suppress the UNCHECKED_CAST warning because the compiler can't possibly know whether we passed the same class name as a type argument.
Then we extend the interface with concrete implementations:
Carrot.kt
class Carrot : VitaminSource<Carrot> {
fun getVitaminA() = println("Vitamin A")
}
Banana.kt
class Banana : VitaminSource<Banana> {
fun getVitaminB() = println("Vitamin B")
}
While extending the classes, you must make sure to pass the same class to the interface otherwise you'll get ClassCastException at runtime:
class Banana : VitaminSource<Banana> // OK
class Banana : VitaminSource<Carrot> // No compiler error but exception at runtime
Test.kt
fun main() {
val carrot = Carrot().getSource()
carrot.getVitaminA()
val banana = Banana().getSource()
banana.getVitaminB()
}
That's it! Hope that helps.
Depending on the exact use case, scope functions can be a good alternative. For the builder pattern apply seems to be most useful because the context object is this and the result of the scope function is this as well.
Consider this example for a builder of List with a specialized builder subclass:
open class ListBuilder<E> {
// Return type does not matter, could also use Unit and not return anything
// But might be good to avoid that to not force users to use scope functions
fun add(element: E): ListBuilder<E> {
...
return this
}
fun buildList(): List<E> {
...
}
}
class EnhancedListBuilder<E>: ListBuilder<E>() {
fun addTwice(element: E): EnhancedListBuilder<E> {
addNTimes(element, 2)
return this
}
fun addNTimes(element: E, times: Int): EnhancedListBuilder<E> {
repeat(times) {
add(element)
}
return this
}
}
// Usage of builder:
val list = EnhancedListBuilder<String>().apply {
add("a") // Note: This would return only ListBuilder
addTwice("b")
addNTimes("c", 3)
}.buildList()
However, this only works if all methods have this as result. If one of the methods actually creates a new instance, then that instance would be discarded.
This is based on this answer to a similar question.
You can do it also via extension functions.
class Foo
fun <T: Foo>T.someFun(): T {
return this
}
Foo().someFun().someFun()