Reputation: 241
I'd like to have an interface and implementing class/object similar to the following:
interface EventBus {
suspend fun <T : Message> publish(message: T)
suspend fun <R : Command, S : CommandResponse> request(command: R): Either<EventbusError, S>
suspend fun close(): Either<EventbusError, Unit>
//? fun <T : Message> subscribe(): Flow<T>
}
object EventBusImpl : EventBus {
private val _eventBus = MutableSharedFlow<Message>()
val messages = _eventBus.asSharedFlow()
override suspend fun <T : Message> publish(message: T) {}
override suspend fun <R : Command, S : CommandResponse> request(command: R): Either<EventbusError, S> {}
override suspend fun close(): Either<EventbusError, Unit> {}
inline fun <reified T:Message> subscribe():Flow<T> = messages.filterIsInstance<T>()
}
I understand that inline functions cannot be over overridden and thus cannot be part of an interface, but as the subscribe()
function is an important part of the API, I'd still like to represent it somehow in the interface, without falling back to passing a Class<T>
as an argument.
How could this be accomplished?
This
interface EventBus {
suspend fun <T : Message> publish(message: T)
suspend fun <R : Command, S : CommandResponse> request(command: R): Either<EventbusError, S>
suspend fun close(): Either<EventbusError, Unit>
suspend fun <T : Message> subscribe(type: Class<T>): Flow<T>
}
of course works, but is not very Kotlin'ish
Upvotes: 2
Views: 2577
Reputation: 752
The comments on your question are correct: It is not possible to have a virtual inlined member as the implementation must be known at compile-time in order to inline it.
However, you can work around it by leaving this virtual member in your interface:
suspend fun <T : Message> subscribe(type: Class<T>): Flow<T>
and adding this inline extension function:
suspend inline fun <reified T : Message> EventBus.subscribe() = subscribe(T::class)
Now you can use subscribe as you intended:
suspend fun foo(bus: EventBus) {
val flow = bus.subscribe<MyMessage>()
}
This has the advantage of keeping subscribe
a virtual member in the original interface (so it must be implemented by subtypes) and better calling syntax via the inline extension function.
Upvotes: 6