Last active
July 14, 2021 15:52
-
-
Save patbeagan1/d121de84880b5176e3eb99c300f6a7be to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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