another great thing: you could use it in combination with a bigger abstraction of ?.
do do great things like allow for specifying on which concrete type a call-chain should continue / allow for call-chains to continue regardless of the concrete type.
Say we would be using unions to implement a result-type (i know, this isn’t the best example, as a Result type is easy to implement with sealed-classes, its just an easy-to-understand example
say you have
val value: [ Int, String ] = 12
// scope-functions (or maybe any method) could take an additional type argument
// which specifies that they will only be called if the concrete value is of a specific type
// and otherwise continue in the call-chain without executing.
val v2: [ Long, String ] = value.<Int>let { it.toLong() }
// you could chain multiple of these to transform all possible types into other types
val v3: [ Long, Boolean ] = value.<Int>let { it.toLong() }
.<String>let { it == "foo" }
// if you transform them in a way that turns all types into the same type
// they could get combined automatically
val v4: Int = value.<String>let { it.toInt() }
this would allow for arbitrary implementations of ADTs to have a syntax simmilar to the beautifully concise null-safe chaining syntax. you could (nearly) implement the nullable type like that:
typealias Nullable<T> = [ T, null ]
val ex1: Nullable<Int> = 123
ex1.<Int>let { println(it) }
val ex2: List<String> = listOf("hi", " 14", "2")
val nums: List<Float> = ex2.mapOnly<Int> {
it.trim()
.toIntOrNull() // <- returns [ Int, null ] here
.<Int>toFloat()
}
this would allow for a lot more expressive use of result-types and simmilar types in general!