Conversation
| @@ -0,0 +1,63 @@ | |||
| package com.kickstarter.libs | |||
|
|
|||
| class Either<out A, out B> private constructor (val left: A?, val right: B?) { | |||
There was a problem hiding this comment.
What do you think of using sealed classes for this?
sealed class Either<out L, out R> {
class Left<out L, out R>(val left: L) : Either<L, R>() {
...
}
class Right<out L, out R>(val right: R) : Either<L, R>() {
...
}
}
Either.Left("Error!")
Either.Right(1)
when(either) {
is Left -> either.left
is Right -> either.right
}Seems to be a common pattern for tagged unions in Kotlin, and prevents even the private ability of instantiating an invalid type.
It's safer!
mbrandonw
left a comment
There was a problem hiding this comment.
amazing! the syntax is a bit funky, but i'll get used to it.
just a few questions...
| @@ -0,0 +1,61 @@ | |||
| package com.kickstarter.libs | |||
|
|
|||
| sealed class Either<out A, out B> { | |||
There was a problem hiding this comment.
should everything be marked as public?
There was a problem hiding this comment.
for posterity public is the default modifier in Kotlin so we get redundant warnings
|
|
||
| @Test fun testEither_Right() { | ||
| val intOrString = Either.Right<Int, String>("hello") | ||
| assertEquals("hello", intOrString.right) |
There was a problem hiding this comment.
are the parens optional? should it not be intOrString.right()?
|
I have my reservations about the way Either is implemented. The use of null types, isLeft() and isRight() allows for a scape hatch from static analysis which should be enforced instead. The encoding to enforce should is similar to the Java version seen here https://github.com/pakoito/RxSealedUnions EDIT: okay, I'm late to the discussion and it'd be great if you gave that project's README a look and gave me an opinion. |
|
@pakoito Not sure I follow. Could you clarify? This is just a starting point and the API is based on our Swift implementation. The only nullables here come from the EDIT: We also don't use
We could very well get rid of these interfaces. |
|
Fair enough them, but I'd remove all of them. |
|
For what it's worth, our implementations are all based on Haskell's Data.Either, which also implement these functions. The types should be statically sound, but if we're missing anything, let us know! |
|
map, mapRight, isLeft and isRight can all be expressed in terms of either(). I didn't know about Haskell's implementation, so probably I am being too anal about it. |
| class Left<out L, out R>(internal val left: L) : Either<L, R>() | ||
| class Right<out L, out R>(internal val right: R) : Either<L, R>() | ||
|
|
||
| fun <C> either(ifLeft: (A) -> C, ifRight: (B) -> C): C = when(this) { |
There was a problem hiding this comment.
Shouldn't this be inline? Also, this function may be called apply.
| package com.kickstarter.libs | ||
|
|
||
| sealed class Either<out A, out B> { | ||
| class Left<out L, out R>(internal val left: L) : Either<L, R>() |
There was a problem hiding this comment.
I'd use Nothing as the unused type in Left and Right,
e.g. class Left< out L >(internal val left: L) : Either<L, Nothing>()
This allows to create an instance of Left with val left = Either.Left(15) without specifying the right type.
fun foo() = when {
1 == 1 -> Either.Left(1)
else -> Either.Right(Exception(""))
}
is correctly infered as Either<Int, Exception>

heck yes!
Say hello to our first Kotlin class. 🤸♂️
what
I ran into this 🤔 💭 moment when setting up our code for native comment support on project updates: since we have comments for either projects or updates, and Swift in fact handles this with its own
Eithertype, 💡, add one to android. Maybe even add it in Kotlin.Things to note:
companion objectallows for us to accessleftandrightas static methods, while keeping our private constructorEitherobjects cannot be created with both values, i.e.!= nullchecks are repeated rather than the definedisLeftandisRightfunctions to satisfy compiler optional warnings ¯_(ツ)_/¯mapLeftdue to time, but coming soon will beflatten(),flatMap(), etc. when we have more time to figure out how to define these functions elegantly without enumss/o to @mbrandonw for helping me explore this, and @christopherwright for the continued moral support