Hi, shouldn’t this be allowed? _*screenshot_1*_ us...
# android
r
Hi, shouldn’t this be allowed? _*screenshot_1*_ using the same generic type works _*screenshot_2*_ just fine, but using a child generic type doesn’t and throws an error anyone got an idea of how to fix it? or another way of perform something like this?
m
Variance is weird and i can never remember which is which but have you tried using
in
or
out
with
T
in
abstract class ViewHolder<T>
?
r
hmm, yeah I always find it confusing, let me try
e
Copy code
abstract class ViewHolder<out T>
when
interface F<T>
,
F<A>
and
F<A.B>
have no relation when
interface F<out T>
,
F<A.B> : F<A>
when
interface F<in T>
,
F<A> : F<A.B>
r
@ephemient well, the issue is that I need to use it as
in
but even
in
doesn’t work
e
then returning a subclass there is unsafe
r
hmm, right, but is there a clean way to do something like this 😅 ?
m
You might need to mark the ViewHolder return type in foo as well.
fun foo(): ViewHolder<in A> {}
e
the types you want say that
Copy code
val vh: ViewHolder<A> = foo()
vh.bind(something that is A but not A.B)
should work but if it requires a
A.B
then it can't
r
@Michaeljon Hayden here is the issue, this is a simple representation just to show you
foo()
might return different type of
ViewHolders
, depending on some value, each one inherits
ViewHolder
with a different generic type from
A
Screen Shot 2022-05-26 at 19.02.13.png
something like this
alright, as it seems unsafe and impossible to do it safely, I fixed it in another way without generics and just did normal
if(item is A.B) bind(item)
m
Sorry, i missed something, Does
foo(): ViewHolder<in A>
not work?
r
yes it doesn’t
here is what I eventually did
m
Copy code
sealed class A {
    class B: A()
    class C: A()
}

abstract class VH<T> {
    abstract fun bind(t: T)
}

class ABViewHolder: VH<A.B>() {
    override fun bind(t: B) {

    }
}

class ACViewHolder: VH<A.C>() {
    override fun bind(t: C) {

    }
}

fun foo(f: A): VH<out A> {
    return when(f) {
        is B -> ABViewHolder()
        is C-> ACViewHolder()
        else -> {}
    }
}
This works but if you're using a when statement you'll need to cover the A case
r
yeah this won’t work either because the function that will call
foo().bind(param)
won’t know which parameter to pass and it won’t be safe as @ephemient said
m
If you're passing in the type to the foo function to get the correct view holder AND that type has all the info you need to do your binding you could do something like this to get around the type safety issue.
Copy code
sealed class Alpha {
    object B: Alpha()
    object C: Alpha()
}

abstract class VH<A: Alpha> {
    abstract val type: A
    abstract fun bind()
}

class ABViewHolder(
    override val type: B
): VH<Alpha.B>() {
    override fun bind() {
        TODO("Not yet implemented")
    }
}

class ACViewHolder(
    override val type: C
): VH<Alpha.C>() {
    override fun bind() {
        TODO("Not yet implemented")
    }
}

fun foo(type: Alpha): VH<out Alpha> {
    return when(type) {
        is B -> ABViewHolder(type)
        is C-> ACViewHolder(type)
    }
}
r
well, yeah that might also solve the problem, thanks for suggesting!
🦜 1