CLOVIS
09/12/2020, 11:57 AMraulraja
09/12/2020, 5:08 PMraulraja
09/12/2020, 5:12 PMCLOVIS
09/12/2020, 6:06 PMComparable/Comparator
by a single interface—which I believe is called Order
?), to have a more streamlined dependency injection system, and I guess that finding a default implementation at compile-time is very convenient because it allows the user not to have to find one by themselves (which is probably nice since this way of writing code does seem like it would use way more interfaces/typeclasses than what we're used to), but I don't see a very big use-case, and your wording makes me think there's one 🤔
Also, my current understanding of typeclasses is that they conceptually are normal interfaces that define behavior, and that the ‘special' thing is that they can be implemented externally (which is coherent with KEEP-87 using a specific keyword for implementation but not for declaration). I guess there's something deeper in there?CLOVIS
09/13/2020, 7:40 PMComparable
.
// This interface already exists
interface Comparable<T> {
fun compareTo(other: T): Int
}
// But for typeclasses we need this one (sorry for the naming, that probably doesn't follow your conventions)
interface ExternalComparable<T> {
fun T.compareTo(other: T): Int
}
Let's say now that we have an arbitrary class
data class Car(...whatever...)
In regular Kotlin, we would write
data class Car(...) : Comparable<Car>
Except that we can't do that if we don't control Car, etc. Typeclasses allow to solve that:
data class Car(...whatever...)
@Given
object CarComparator : ExternalComparable<Car> {
override fun Car.compareTo(other: Car): Int
}
If I understand your comments correctly, the Given annotation allows to tell the compiler “this is the default implementation of ExternalComparable
for `Car`s, let me use it implicitly” (and that only works in your own scope to not break everything).
Now, if I understand correctly, the Arrow Meta compiler let's you write
val c = Car(...)
val d = Car(...)
val r = c.compareTo(d)
Here, no need to specify that the implementation we use is CarComparator
, the compiler finds it by itself (assuming we're in the right scope).
If all of this is correct, I have a few questions:
• What if we want to use another implementation than the Given
one? I think it was mentioned in the wiki that typeclasses were useful to have multiple implementations of interfaces (eg. to sort based on different criterion in different cases).
• If I'm not wrong, this solution allows to call implemented functions fine, but I don't think it satisfies is
relationships:
val c = Car(...)
if (c is Comparable)
...
It seems to me like that would be useful, and that the only solution would be to have the compiler be able to generate the ‘extension interface' syntax from any regular interface, so it could do the link itself?raulraja
09/13/2020, 9:22 PMis
checks because that is a runtime check which implies a subtype relationship:
@Coercion fun Car.comparable(): Comparable<Car> = ...
val car1: Car = Car()
val c: Comparable<Car> = car1 //ok by coercion
val result = car1 > car2 //> from Comparable available by extension
raulraja
09/13/2020, 9:23 PMraulraja
09/13/2020, 9:24 PMWhat if we want to use another implementation than thewhen used as value argument in functions or constructors you can always pass the instance manually or provide an internal override if it’s not in value argument position so it applies locally to the whole moduleone?Given
raulraja
09/13/2020, 9:25 PMraulraja
09/13/2020, 9:25 PMCLOVIS
09/21/2020, 10:01 AMfilter
and sort
)raulraja
09/21/2020, 10:33 AMraulraja
09/21/2020, 10:36 AMraulraja
09/21/2020, 10:39 AM