I think I'm missing something somewhere, please te...
# arrow
c
I think I'm missing something somewhere, please tell me if I'm asking too many questions... My current understanding is that the concept of typeclasses is, essentially: • A way to make an object you don't control implement any interface you want • The next step in polymorphism (via Monad, etc, that allow to group Promise, Collections, Map etc together, which allows even more polymorphism than regular Collections can) • The idea behind it is to represent ‘behaviors', and it solves for example Java's duality of Comparable/Comparator (a Comparator essentially being an external implementation of the Comparable interface). Having this be at the language's level allows for less code duplication, and more generalization, as the same pattern of “a
sort
function that sorts the objects based on their own implementation, and a second
sort
function that sorts based on an external comparator” can be applied to many other interfaces, such as Eq, Hash, Print. If that's the concept, if I wanted to try to implement this in Kotlin, I would go with something like:
Copy code
infix inline fun <reified O, reified T>.withTypeclass(typeclass: T) =
  object : O by this, T by typeclass
I believe that's not legal Kotlin syntax, but I also think it wouldn't be too hard to add this via a compiler plugin (since it's just generating a new object with compile-time known types, I don't expect it to be that hard). The idea came from the recommendation on the documentation: https://arrow-kt.io/docs/patterns/dependency_injection/#composing-dependencies
Copy code
This would allow to write code like
val a = Car() withTypeclass someOrderForCars()
listOf(a).sorted() // or similar
To me, this solves all above use-cases, looks like normal Kotlin (pretty close to no code generation, no hidden complexity...). I don't see any negative sides to this approach. Of course, I'm still a student, and I have a very light background in functional programming, so I expect that there's a lot that's not apparent to me... The Arrow documentation recommends a completely different way (https://arrow-kt.io/docs/typeclasses/intro/), which if I understand correctly has the benefit of not needing a compiler plugin, but it requires to create a split between ‘typeclass' and ‘interface' that I don't see a need for. KEEP-87 seems to be yet another way of implementing this, which exclusively uses function parameters to do the combination I showed before, which would mean (if I understand correctly), that it wouldn't be able to send an ‘external implementation' to a function not specifically written with that purpose in mind. KEEP-87 also introduces a way to decide a default external implementation at compile-time, which is yet another concept. At this point I'm a bit lost on what the pro/cons of each solution are, assuming I'm not comparing pears to oranges... It seems to me like the first solution would be the easiest one to teach to Kotlin developers without FP experience, since it's so similar to what the language already does with Comparable/Comparator, so I guess that there's a good reason this is not what KEEP-87 looks like, but I don't think I have the needed experience to understand why that is... I'm very curious as to what expert's thought process looks like on these topics, sorry for this wall of text 😅
Thanks, should I just go in that channel and link this post?
r
Yes, what I ment to say too is that your use case already exists in meta and if you or anyone else is interested I'll be happy to show you the differences between the approaches and what is possible with meta. Among other things we need people to test it and see if it works for their use case and how it could be improved. Feel free to join that channel as well if you are interested in the evolution of meta where type classes and other type system features we build for arrow are discussed
c
Thanks ^^
t
You focused a lot on usage, which is important, but at the concept itself it’s just “different way to express interfaces”, current OOP languages a class must explicit tell its interfaces, while whit the type classes of functional languages, you can define anywhere which interface a type implements (and implement what the interface needs). What people usually call “ad-hoc polymorphism”. So it’s just the question of who/what should define the implementations of the Interface. Your use case fits nicely with the concept.
c
I think I understand what it means semantically, the problem is that I'm trying to use it in code now and I'm lost as to how I should write it 😅