https://kotlinlang.org logo
Title
m

Mark

03/12/2021, 3:37 AM
Is there a better way to define this class? Note, I don’t want to use a generic parameter, because the type of
rawItem
should not be exposed (and I would rather pass around
LazyItems
than
LazyItems<Foo>
). In other words, I want a kind of private
R
generic.
class LazyItems private constructor(
    private val rawItems: List<Any>,
    private val processItem: (Any) -> Item,
) {

    fun consumeItem(): Item {
        val rawItemToConsume = someFun(rawItems) // Any
        return processItem(rawItemToConsume)
    }

    companion object {
        operator fun <R: Any> invoke(
            rawItems: List<R>,
            processItem: (R) -> Item
        ) = LazyItems(rawItems) {
            processItem(it as R)
        }
    }
}
It’s a shame you can’t do something like:
class LazyItems constructor <R : Any> (
    private val rawItems: List<R>,
    private val processItem: (R) -> Item,
) {
j

Joel

03/12/2021, 9:48 PM
I think what you wrote is fine. It's very similar to a lazy iterator implementation I wrote.
class MappedIterator<T, R>(
    private val delegate: Iterator<T>,
    private val transform: (T) -> R,
) : Iterator<R> {
    override fun hasNext() = delegate.hasNext()

    override fun next() = transform(delegate.next())
}

class MappedIterable<T, R>(
    private val delegate: Iterable<T>,
    private val transform: (T) -> R,
) : Iterable<R> {
    override fun iterator() = MappedIterator(delegate.iterator(), transform)
}

fun <T, R> Iterable<T>.mapLazily(transform: (T) -> R): Iterable<R> = MappedIterable(this, transform)
I don't follow why passing around
LazyItems<Foo>
is an issue. That's using the language as intended, for better or for worse.
m

Mark

03/13/2021, 3:09 AM
Thanks Joel. It’s simply that it doesn’t make sense to expose the generic to the class user, since none of the functions or properties deal with that type. What I ended up doing was encapsulating the R-specific logic in a generic class private to
LazyItems
.