Hey gents, I’m designing an interprocess thing for our application and I’ve got it working pretty well, but I’m wondering about the exact semantics of connections.
given the classes:
class SessionFactory {
fun createSession(someConfig: Config): Session
}
class Session: Closeable {
fun exchange(request: Message): /*response:*/ Message
//a couple other methods for fire-and-forget functionality
}
in point of fact, our actual API has a boatload of
suspend
’s in it, but I dont think that’s relevant here.
My happy-path code can then look like
@UIFramework fun onSyncButtonClick(event: Event){
val uiRelatedValues = sessionFactory.create(config).use { session ->
//suspending code block that hits this device a lot and builds useful information for this view.
}
}
which is all very nifty, except I’m wondering what the best way to express an error here.
I could have the return type from SessionFactory.create()
be a sealed class with one of those sealed classes being some kind of error wrapper. The idiom then becomes
class SessionFactory {
fun createSession(someConfig: Config): SessionOrError
}
sealed class SessionOrError: Closeable {
data class Error(val cause: ProblemDescription): SessionOrError {
override fun close(){}
}
class Session: SessionOrError {
fun exchange(request: Message): Message
//...
}
}
@UIFramework fun onSyncButtonClick(event: Event){
val uiRelatedValues = sessionFactory.create(config).use { sessionOrError ->
when(sessionOrError){
is Error -> doPopupOrLogOrSomethingClever(sessionOrError.error)
is ValidSession -> {
//previous code block
}
}
//could also reduce indentation with
val session = if(sessionOrError is Error){
doPopupOrLogOrSomethingClever(sessionOrError.error)
return@use
} else (sessionOrError as Session).session
}
}
I could use funktional’s either type:
class SessionFactory {
fun createSession(someConfig: Config): Either<Session, Error>
}
@UIFramework fun onSyncButtonClick(event: Event){
val uiRelatedValues = sessionFactory.create(config).mapLeft { error ->
doPopupOrLogOrSomethingClever(error)
}
uiRelatedValues.mapRight { it.use { session ->
//...
}}
}
I suppose I could also up the arity and proivde a custom use
method, such that we get something like
@UIFramework fun onSyncButtonClick(event: Event){
val uiRelatedValues = sessionFactory.create(config).customUse { session, error ->
if(error != null){
doPopup(error)
}
else if (session != null){
//...
}
}
}
if you were a dev on my team, what would you like to see? what would you hate to see? How comfortable are you with something like an Either
type?