Skip to content

Instantly share code, notes, and snippets.

@patbeagan1
Last active July 14, 2021 15:52
Show Gist options
  • Save patbeagan1/d121de84880b5176e3eb99c300f6a7be to your computer and use it in GitHub Desktop.
Save patbeagan1/d121de84880b5176e3eb99c300f6a7be to your computer and use it in GitHub Desktop.
/**
* You can edit, run, and share this code.
* play.kotlinlang.org
*/
// --- implementation of a union in kotlin
abstract class UnionBase<T>(s: Set<T?>) {
init {
val c = s.count { it != null }
if (c != 1) throw Exception("Unions must have exactly one type, saw $c")
}
val value = s.first { it != null }
}
// --- union
typealias Union<A, B> = UnionTyped<Any, A, B>
class UnionTyped<T, A : T, B : T> private constructor(
val a: A? = null,
val b: B? = null
) : UnionBase<T?>(setOf(a, b)) {
companion object {
fun <T, A : T, B : T> ofA(a: A) = UnionTyped<T, A, B>(a = a)
fun <T, A : T, B : T> ofB(b: B) = UnionTyped<T, A, B>(b = b)
}
}
inline fun <reified T, reified A : T, reified B : T> UnionTyped<T, A, B>.resolve(
fa: (A) -> Unit = {},
fb: (B) -> Unit = {}
) = when (value) {
is A -> fa(value)
is B -> fb(value)
else -> throw Exception("Wrong type")
}
//--- union 3
typealias Union3<A, B, C> = Union3Typed<Any, A, B, C>
class Union3Typed<T, A : T, B : T, C : T> private constructor(
val a: A? = null,
val b: B? = null,
val c: C? = null
) : UnionBase<T?>(setOf(a, b, c)) {
companion object {
fun <T, A : T, B : T, C : T> ofA(a: A) = Union3Typed<T, A, B, C>(a = a)
fun <T, A : T, B : T, C : T> ofB(b: B) = Union3Typed<T, A, B, C>(b = b)
fun <T, A : T, B : T, C : T> ofC(c: C) = Union3Typed<T, A, B, C>(c = c)
}
}
inline fun <reified T, reified A : T, reified B : T, reified C : T> Union3Typed<T, A, B, C>.resolve(
fa: (A) -> Unit = {},
fb: (B) -> Unit = {},
fc: (C) -> Unit = {}
) = when (value) {
is A -> fa(value)
is B -> fb(value)
is C -> fc(value)
else -> throw Exception("Wrong type")
}
// --- demo
typealias Y = UnionTyped<Any, Int, Float>
class X(val u: UnionTyped<Any, Int, Float>) {
companion object {
fun ofA(t: Int) = X(Union.ofA<Any, Int, Float>(t))
}
}
fun main() {
// creates a union, which resolves to type Any
val a = UnionTyped.ofA<Any, Int, Boolean>(1)
// creates a union which resolves to the 2nd real type of Y, which is Float
val b: Y = Y.ofB(2f)
// creates a union which resolves to the 2nd real type, which is Boolean
val c: Union<Int, Boolean> = Union.ofB(false)
val x = X.ofA(1)
val aa: UnionTyped<Number, Int, Float> = Union.ofB(5f)
println("Hello, world!")
listOf(a, b, c, x.u, aa).forEach {
it.value.toString().let { println(it) }
}
// testing that we can resolve the contents of the union
val z: Union3Typed<Any, Int, Float, Boolean> = Union3.ofC(true)
println()
z.resolve({ println("A: $it") }, { println("B: $it") }, { println("C: $it") })
println()
var aaa = mutableListOf<Union<Int, String>>()
(0..10).forEach {
if (it % 2 == 0) {
aaa.add(Union.ofA(it))
} else {
aaa.add(Union.ofB("test"))
}
}
aaa.forEach { println(it.value.toString()) }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment