This message was deleted.
# getting-started
s
This message was deleted.
s
Typically this is done with the
@UnsafeVariance
annotation — for example the built-in collections do this
You’re right, I misunderstood the question, sorry
👍 1
y
Apparently this works:
Copy code
sealed class Bounds<in T : Comparable<T>> {
    abstract operator fun contains(value: T): Boolean
}
object Unbounded : Bounds<Comparable<Comparable<*>>>() {
    override fun contains(value: Comparable<Comparable<*>>) = true
}
🤯 1
👌 1
Not sure why the nested `Comparable`s are needed, but hey it runs at least
s
Another solution is
Copy code
class Unbounded<in T : Comparable<T>> : Bounds<T>() {
    override fun contains(value: T) = true
}
if you can live with it not being a singleton
y
I would've expected that
Comparable<*>
would be a subtype of
Comparable<T> where T: Comparable<T>
but I guess not?
This also works:
Copy code
sealed class Bounds<in T : Comparable<T>> {
    abstract operator fun contains(value: T): Boolean
}
object Unbounded : Bounds<Comparable<Any?>>() {
    override fun contains(value: Comparable<Any?>) = true
}
Which I think (maybe?) makes more sense. Comparable's T is
in
, and so
Comparable<*>
is in reality
Comparable<Nothing>
, which I think then isn't a subtype of
Comparable<Comparable<Nothing>>
because it can only accept arguments of type
Nothing
. Hopefully that makes a bit more sense lol! Generic variance is truly
out
of this world...
😆 1
I think the easiest solution is this:
Copy code
sealed class Bounds<in T : Comparable<T>> {
    abstract operator fun contains(value: T): Boolean
}

object Unbounded : Bounds<Comparable<Any?>>() {
    override fun contains(value: Comparable<Any?>) = true
}

fun <T: Comparable<T>> unbounded(): Bounds<T> = Unbounded as Bounds<T>

interface B : Comparable<B>

class A(val spec: Bounds<B> = unbounded())
m
late response, but this looks a lot like my range custom range implementation that looks like this for 'unbounded' ranges:
Copy code
sealed interface Range<T : Comparable<T>>{
    interface Open<T : Comparable<T>> : Range<T> {
        override fun contains(value: T) = true
    }
}

internal object OpenRange = Range.Open<Nothing>

fun <T : Comparable<T>> openRange() = Range.OPEN as Open<T>
its akin to how List<T> and emptyList() is used by kotlin self, you only have a cast problem, but you'll have to surpress that. Kotlin itself uses unsafevariance and stuff to surpress the cast warnings. The main takeaway is that unbounded should probably be Nothing, not Any?