janvladimirmostert
08/08/2022, 9:18 PMdoSomething<T1, Tn, ..., Tn>(...)
that would output On
In other words, if I provide 5 generics, I want an O5<T1, T2, T3, T4, T5>
as output and if I define 1 generic, I want O1<T1>
as outputGiorgos Makris
08/08/2022, 9:46 PMO
different from a tuple?janvladimirmostert
08/08/2022, 9:56 PM(a, b, c) = doSomething<Int, String, Boolean>(.....)
99 is just for illustration purposes, probably don't need more than 20
What mechanism would be able to translate function<T1,T2,T3>() to a tuple of 3 items ?Giorgos Makris
08/08/2022, 9:58 PMjanvladimirmostert
08/08/2022, 10:00 PMGiorgos Makris
08/08/2022, 10:02 PMjanvladimirmostert
08/08/2022, 10:03 PMGiorgos Makris
08/08/2022, 10:04 PMjanvladimirmostert
08/08/2022, 10:04 PMGiorgos Makris
08/08/2022, 10:04 PMjanvladimirmostert
08/08/2022, 10:05 PMGiorgos Makris
08/08/2022, 10:06 PMmapof(Pair(O5::class, { o5 -> /* do submit stuff */ }))
o
or interface for it to be able to have a common type for the mapjanvladimirmostert
08/08/2022, 10:08 PMsubmit
itself a class, mmmGiorgos Makris
08/08/2022, 10:10 PMO
?janvladimirmostert
08/08/2022, 10:11 PMGiorgos Makris
08/08/2022, 10:12 PMjanvladimirmostert
08/08/2022, 10:12 PMGiorgos Makris
08/08/2022, 10:13 PMjanvladimirmostert
08/08/2022, 10:14 PMval result = submit(
i = T(BLAH1("blah1"), BLAH2("blah2")),
o = T(BLAH1, BLAH1, BLAH2)
)
// want
val (a: BLAH1, b: BLAH1, c: BLAH2) = result
// instead getting
val (a: BLAH1.Companion, b: BLAH1.Companion, c: BLAH2.Companion) = result
a
now contains BLAH1.Companion
instead of BLAH1
Giorgos Makris
08/08/2022, 10:17 PMjanvladimirmostert
08/08/2022, 10:18 PMGiorgos Makris
08/08/2022, 10:18 PMjanvladimirmostert
08/08/2022, 10:21 PMval result = submit(
i = T(BLAH1("blah1"), BLAH2("blah2")),
o = T(BLAH1(null), BLAH1(null), BLAH2(null))
)
I get the correct output types, but that means creating an unnecessary instance for each output typeval result = submit(
i = T(BLAH1("blah1"), BLAH2("blah2")),
o = T3<BLAH1, BLAH1, BLAH2>()
)
and be done with it, but I'm trying to not specify that 3Giorgos Makris
08/08/2022, 10:25 PMjanvladimirmostert
08/08/2022, 10:26 PM(a, b, c) = submit<O3<T1, T2, T3>>(value1, value2, ...valuen)
is probably not that bad, I'll just have to convince myself that explicitly specifying the number of outputs is awesome, hahahaGiorgos Makris
08/08/2022, 10:27 PMjanvladimirmostert
08/08/2022, 10:28 PMGiorgos Makris
08/09/2022, 7:02 AMYoussef Shoaib [MOD]
08/09/2022, 7:12 AMfun <T1> doSomething(...): O1<T1>
fun <T1, T2> doSomething(...): O2<T1, T2>
You can easily generate this lol. What I've done in the past is written some Kotlin code that generates it, and placed it at the bottom of that file.janvladimirmostert
08/09/2022, 7:30 AMYoussef Shoaib [MOD]
08/09/2022, 7:48 AMfun <T1> doSomething(vararg args: Type): O1<T1>
fun <T1, T2> doSomething(vararg args: Type, unit1: Unit = Unit): O2<T1, T2>
fun <T1, T2, T3> doSomething(vararg args: Type, unit1: Unit = Unit, unit2: Unit = Unit): O3<T1, T2, T3>
Again, really easy to code generate. Overload resolution then works based on how many type arguments you specify.phldavies
08/09/2022, 8:09 AMsealed interface TypeMarker<out T1, out T2, out T3, out T4, out T5> {
object IMPL : TypeMarker<Nothing, Nothing, Nothing, Nothing, Nothing>
}
fun <T1> doSomething(vararg args: String, typeMarker: TypeMarker<T1, Nothing, Nothing, Nothing, Nothing> = TypeMarker.IMPL): T1 = TODO()
fun <T1, T2> doSomething(vararg args: String, typeMarker: TypeMarker<T1, T2, Nothing, Nothing, Nothing> = TypeMarker.IMPL): Pair<T1, T2> = TODO()
fun <T1, T2, T3> doSomething(vararg args: String, typeMarker: TypeMarker<T1, T2, T3, Nothing, Nothing> = TypeMarker.IMPL): Triple<T1, T2, T3> = TODO()
fun <T1, T2, T3, T4> doSomething(vararg args: String, typeMarker: TypeMarker<T1, T2, T3, T4, Nothing> = TypeMarker.IMPL): Tuple4<T1, T2, T3, T4> = TODO()
fun <T1, T2, T3, T4, T5> doSomething(vararg args: String, typeMarker: TypeMarker<T1, T2, T3, T4, T5> = TypeMarker.IMPL): Tuple5<T1, T2, T3, T4, T5> = TODO()
fun main() {
val a = doSomething<String>()
val (b, c) = doSomething<Int, Long>()
val (d, e, f) = doSomething<Byte, List<String>, Set<String>>()
}
janvladimirmostert
08/09/2022, 8:23 AMinline fun <reified Z1> doSomething(
vararg args: String, typeMarker: TypeMarker<Z1, Nothing, Nothing, Nothing, Nothing> = TypeMarker.IMPL
): Z1 {
Z1::class.Companion ???
TODO()
}
@JvmInline
value class INT4(override val value: ByteArray): Encodable {
constructor(value: Int) : this(value.toString().toByteArray())
constructor(value: String) : this(value.toByteArray())
companion object: Decodable {
override val code = 23
}
I need to be able to get the code of that Decodable somehow
inline fun <reified Z1: Decodable> doSomething(
vararg args: Encodable, typeMarker: TypeMarker<Z1, Nothing, Nothing, Nothing, Nothing> = TypeMarker.IMPL
): Z1 {
Z1::code << ----- I think this is the only missing piece
TODO()
}
so that I can do a lookup, if it's code 23, I know I should grab 4 bytes in order to return INT4fun <T> mapValue(code: Int, value: String): T {
// .....
}
inline fun <reified Z1> doSomething(
vararg args: Any, typeMarker: TypeMarker<Z1, Nothing, Nothing, Nothing, Nothing> = TypeMarker.IMPL
): Z1 {
return when (Z1::class.java.name) {
INT4::class.java.name -> mapValue(INT4.code, "1234")
INT8::class.java.name -> mapValue(INT8.code, "5678")
else -> TODO("add more types")
}
}
with about 50 types, that when
is not a great solution
val a:INT4 = doSomething<INT4>(INT4(123), INT8(122312))
a
now correctly contains INT4(123)
Similarly for 2 outputs
inline fun <reified Z1, reified Z2> doSomething(
vararg args: Any, typeMarker: TypeMarker<Z1, Z2, Nothing, Nothing, Nothing> = TypeMarker.IMPL
): Pair<Z1, Z2> {
val z1 = when (Z1::class.qualifiedName) {
INT4::class.qualifiedName -> INT4(INT4.code)
INT8::class.qualifiedName -> INT8(INT8.code)
else -> TODO("add more types")
} as Z1
val z2 = when (Z2::class.qualifiedName) {
INT4::class.qualifiedName -> INT4(INT4.code)
INT8::class.qualifiedName -> INT8(INT8.code)
else -> TODO("add more types")
} as Z2
return Pair(z1,z2)
}
val (b, c) = doSomething<INT4, INT8>()
println(b)
println(c)
Outputs:
INT4(23)
INT8(20)
🎉
now just to optimize that mapping inside doSomething (without using reflection)phldavies
08/09/2022, 9:23 AMwhen(Z1::class) { INT4::class -> INT4(INT4.code) }
)val code = Z1::class.companionObjectInstance as? Decodable)?.code ?: error("not decodable type")
Giorgos Makris
08/09/2022, 9:27 AMjanvladimirmostert
08/09/2022, 9:29 AMwhen
with 50 such types the fastest way to do this?
I was hoping there's a way to do Z1.code and then use an Array lookup
val lookup = Array()
lookup[23] = { INT4(it) }
lookup[20] = { INT8(it) }
I guess I'll have to benchmark the difference in speed between a 100k lookups using reflection to get the code an do the map lookup VS just a giant "switch-case"phldavies
08/09/2022, 9:29 AMwhen
just as fast as an array lookup by index - possibly fasterjanvladimirmostert
08/09/2022, 9:32 AMYoussef Shoaib [MOD]
08/09/2022, 12:58 PMsealed interface
and a nested object IMPL
thing) and I literally didn't think of that as a solution lol! I agree that using TypeMarker is probably a good idea here.
Btw, you can define multiple arities of TypeMarker as typealiases with a singular object IMPL
and that'll save you from having to use a lot of `Nothing`sjanvladimirmostert
08/09/2022, 1:11 PMsealed class TW5<out T1, out T2, out T3, out T4, out T5> {
@PublishedApi internal object IMPL: TW5<Nothing, Nothing, Nothing, Nothing, Nothing>()
}
typealias TW4<T1, T2, T3, T4> = TW5<T1, T2, T3, T4, Nothing>
typealias TW3<T1, T2, T3> = TW4<T1, T2, T3, Nothing>
typealias TW2<T1, T2> = TW3<T1, T2, Nothing>
typealias TW1<T1> = TW2<T1, Nothing>
Youssef Shoaib [MOD]
08/09/2022, 3:27 PMjanvladimirmostert
08/09/2022, 3:39 PM