Rob Elliot
05/16/2025, 9:55 AMby lazy
to memoize calculated vals on an abstract class, not on an interface?
// compiles, only runs expensiveOperationOn(things) once
abstract class FooAbstractClass {
abstract val things: List<Thing>
val thingsSupportSomething by lazy { expensiveOperationOn(things) }
}
// compiles but fails at runtime
abstract class FooAbstractClassFails {
abstract val things: List<Thing>
val thingsSupportSomething = expensiveOperationOn(things)
}
// does not compile
interface FooInterfaceDoesNotCompile {
val things: List<Thing>
val thingsSupportSomething = expensiveOperationOn(things)
}
// does not compile
interface FooInterfaceDoesNotCompileByLazy {
val things: List<Thing>
val thingsSupportSomething by lazy { expensiveOperationOn(things) }
}
// compiles, runs expensiveOperationOn(things) every time `thingsSupportSomething` is dereferenced
interface FooInterface {
val things: List<Thing>
val thingsSupportSomething: Boolean get() = expensiveOperationOn(things)
}
Joffrey
05/16/2025, 9:58 AMthingsSupportSomething
without any initializer, and then implement it with a private/internal abstract class to handle laziness if need be.
The fact that the property is computed doesn't matter to the interface definition. It's an implementation detailRob Elliot
05/16/2025, 9:59 AMJoffrey
05/16/2025, 9:59 AMJoffrey
05/16/2025, 10:00 AMRob Elliot
05/16/2025, 10:04 AMcompiles but fails at runtime
problem) but also because they decouple better - you can make anything implement an interface.
But computed values without repetition are a bit of a pain.
I suppose I could do the interface & base abstract class pattern, but there's quite a lot of repetition there too 🙂.Rob Elliot
05/16/2025, 10:08 AMsealed interface Foo
abstract class BaseFoo : Foo
class Foo1(): BaseFoo()
class Foo2(): BaseFoo()
I'd like to prevent clients referring to BaseFoo
, its existence is an implementation detail and I don't want to commit to it continuing to exist... but I don't think I can hide it if I want Foo
, Foo1
& Foo2
to be public?Youssef Shoaib [MOD]
05/16/2025, 11:05 AMby
interface delegation I guess, but it has its pitfallsRob Elliot
05/16/2025, 11:08 AMList<Thing>
into a Things
class which could have the expensiveOperationOn
function on it, allowing it to memoize the result. So I can lose the intermediate abstract class and have this:
interface FooInterface {
val things: Things
val thingsSupportSomething: Boolean get() = things.memoizedExpensiveOperation()
}