Hunter
08/17/2025, 3:05 PM?
and elvis ?:
operators? This is already kinda part of the rich error proposal, but it only works for error unions there, but could also just be useful on its own. It's essentially just syntax sugar for a monad map
.
Basic example (not sold on this syntax):
sealed interface ParseResult<T> {
data class Success(val value: T) : ParseResult<T>
data class FormatError(val expected: String, val got: String) : ParseResult<Nothing>
data class Failure(val cause: Exception) : ParseResult<Nothing>
operator fun <R> question(operation: T.() -> R): ParseResult<R> =
if (this is Success) this.value.operation() else this
operator fun <R : T> elvis(operation: () -> R): T =
when (this) {
Success -> this.value
else -> operation()
}
}
fun Foo.Companion.parse(str: String): ParseResult<Foo> = //...
fun example() {
val foo: Foo = Foo.parse("hello world")?.doSomething() ?: Foo.None
}
I don't really like how the elvis overload works here, but I think it gets the idea across.Youssef Shoaib [MOD]
08/17/2025, 3:27 PMerror data class FormatError(val expected: String, val got: String)
error data class Failure(val cause: Exception)
typealias ParseResult<T> = T | FormatError | Failure
fun Foo.Companion.parse(str: String): ParseResult<Foo>
fun example() {
val foo: Foo = Foo.parse("hello world")?.doSomething() ?: Foo.None
}
Hunter
08/17/2025, 3:37 PMerror
classifier.Youssef Shoaib [MOD]
08/17/2025, 3:38 PMHunter
08/17/2025, 3:42 PM?
overloading was added, then all null-safe calls could be made into a simple extension function included in the prelude like so:
operator fun <T : Any, R> T?.question(operation: T.() -> R): R? =
if (this == null) null else operation(this)
Compiler optimizations could be added for it, of course, but by making this an overload suddenly safe calls aren't a special case for unions, but instead just a normal operation.Youssef Shoaib [MOD]
08/17/2025, 3:45 PMnull
as an error object
does the same in the case of Rich Errors. The idea is extending null
to be able to have info inside.Hunter
08/17/2025, 3:51 PMT | null
. But then I guess you could just say typealias T? = T | null
. Regardless, yes I think rich errors lead to a nicer syntax, but like I was saying if they don't get added this is a nice alternative imo.Youssef Shoaib [MOD]
08/17/2025, 3:54 PMResult<ParseError<Foo>>
vs ParseError<Result<Foo>>
handling it will be different, even though they're really the same thing, but this doesn't happen with unions since they're commutative)