<@U16NLGHQ8> When a compiler uses two different ty...
# announcements
r
@igor.wojda When a compiler uses two different types as input to a function or class that is parametric and incudes type arguments the compiler needs to infer the intersection type of the different values provided to determine the type of the receiver. In the link above the compiler is trying to determine the inferred type for
list
using both
handlers
and
ErrorHandler
type information and computing the intersection based on the hierarchy of those two applied types. In the first case
handlers
uses an interface that declares type arguments in contravariant position
in
. The compiler seems to be fine finding the intersection but it's bailing at runtime so the generated bytecode is probably incorrect where it has to do the appropriate cast but this last part is a wild guess.
👍 2
i
Ah Now I remember it the same as
listOf(Pair(1,2), Pair("A", "B"))
-> insertion type
Pair<Any, Any>
r
right
Any
is the upper bound of
String
and
Int
because that is where they both meet in a common super type.
Kotlin can't abstract over arity but with a representable HList you could do:
Copy code
val hl: HList<Pair<Int, Int>, Pair<String, String>> = hListOf(Pair(1,2), Pair("A", "B"))
We are building one for generic derivation in Arrow.
i
OK, I understand the code although I lost the point (intention) of your 2 last messages
r
The intention is that if you can abstract over arity of type arguments you can preserve their information without having to compute an intersection type or upperbound for those types such as HList that are able to preserve that type information. The you can express that a List contains all these types or a Union contains only one of all these list of types. Since Kotlin does not support it we are gonna use an annotation processor to support preserving type information which is useful for many techniques for example creating encoders and decoders for data classes automatically for json and serialization that do not rely on reflection. Heterogeneous list, TupleN etc can be used to automatically derive machinery you need for your app and library for types like data classes or sealed classes because those as encoded can go back and forth without loosing type information. Was just commenting that we were doing that and it's somewhat related to intersection types but no worries 🙂.
👍 1
👌 1
i
Isn’t this Kotlin code ‘abstraction over arty of type arguments’ ?
Copy code
fun <T> copyWhenGreater(list: List<T>, threshold: T): List<String>
    where T : CharSequence,
          T : Comparable<T> {
    return list.filter { it > threshold }.map { it.toString() }
}
This meet your criteria that “you can preserve their information without having to compute an intersection type or upperbound”
r
Not really because what would be the type of
listOf(1, "a", 'c')
?
that would not yield
HList3<Int, String, Char>
When we say abstracting over arity we mean that you we can preserve type information regardless of the number of arguments of diferent types we feed into a function or class construction
This allows us to state that for each for example data class you can go to HList and back without loosing information:
Copy code
data class Person(val name: String, val age: Int) <=> HList2<String, Int>
This opens the door to allows to define type class instances over HListN arities which are then automatically applicable to all data classes because of this isomorphism in the structure of these types.
An example of where this technique would be useful is Decoder/Encoders for serialization.
Without relying in runtime reflection, just type class evidences.
i
thanks for explanation
👍 1