Gilles Barbier
06/03/2020, 5:17 PMA
, B
, C
, ... (for our use-case, they are describing different type of Message)
I have a function f
defined by f(msg: A) : AP
, f(msg: B) : BP
, f(msg: C) : CP
... that convert those message into another format (Avro classes)
My issue is that I have no way to apply this function to an arbitrary collection of A
, B
, C
, ..
setOf(msgA, msgB, msgA, msgC, msgB..).forEach { f(it) }
because it
is then of type Any
(despite each f(it)
individually is valid, the syntax is invalid)
Would be happy to receive suggestion 🙂 about how to handle thisAnimesh Sahu
06/03/2020, 5:19 PMGilles Barbier
06/03/2020, 5:25 PMSandesh Baliga
06/04/2020, 5:39 AMMatteo Mirk
06/04/2020, 8:56 AMf()
function. In the end polymorphism is what will save you from ifs/whenGilles Barbier
06/04/2020, 8:59 AMfun convertToAvro(message: Message): SpecificRecordBase = when (message) {
is CancelJob -> convertToAvro(message)
is DispatchJob -> convertToAvro(message)
is JobAttemptCompleted -> convertToAvro(message)
is JobAttemptDispatched -> convertToAvro(message)
is JobAttemptFailed -> convertToAvro(message)
is JobAttemptStarted -> convertToAvro(message)
is JobCanceled -> convertToAvro(message)
is JobCompleted -> convertToAvro(message)
is JobCreated -> convertToAvro(message)
is JobDispatched -> convertToAvro(message)
is JobStatusUpdated -> convertToAvro(message)
is RetryJob -> convertToAvro(message)
is RetryJobAttempt -> convertToAvro(message)
is RunJob -> convertToAvro(message)
}
Gilles Barbier
06/04/2020, 8:59 AMSandesh Baliga
06/04/2020, 9:02 AMSandesh Baliga
06/04/2020, 9:06 AM(message as MessageType).convertToAvro
Gilles Barbier
06/04/2020, 10:00 AMAnimesh Sahu
06/04/2020, 10:01 AMAnimesh Sahu
06/04/2020, 10:02 AMGilles Barbier
06/04/2020, 10:09 AMfun convertToAvro(message: Message): SpecificRecordBase = message.test()
fun Message.test() : SpecificRecordBase = convertToAvro(this)
Gilles Barbier
06/04/2020, 10:09 AMGilles Barbier
06/04/2020, 10:21 AMMatteo Mirk
06/04/2020, 10:45 AMinterface Message {
fun convertToAvro(): SpecificRecordBase
}
class CancelJob : Message {
override fun convertToAvro(): SpecificRecordBase {
TODO("create avro record")
}
}
class DispatchJob : Message {
override fun convertToAvro(): SpecificRecordBase {
TODO("create avro record")
}
}
// and so on...
or
Use a sealed class
sealed class Message {
abstract fun convertToAvro(): SpecificRecordBase
class CancelJob : Message() {
override fun convertToAvro(): SpecificRecordBase {
TODO("create avro record")
}
}
class DispatchJob : Message() {
override fun convertToAvro(): SpecificRecordBase {
TODO("create avro record")
}
}
// and so on...
}
then in any case you can convert various message types in the same collection:
setOf<Message>(...).forEach { it.convertToAvro() } // polymorphic call is dynamically dispatched to runtime type
In this way, whenever you add a new Message subtype the client code above won’t break.Gilles Barbier
06/04/2020, 11:05 AMMessage
is not under my control (from another library) but convertToAvro
is ?Matteo Mirk
06/04/2020, 1:17 PMGilles Barbier
06/04/2020, 1:18 PM