Nat wrote a good summary of Kotlin on his blog recently and this remark in particular:
However, there’s no way to write a generic function that sums its parameters, because add is not defined on an interface that can be used as an upper bound.
I wonder if we could extend the concept of “extension functions” to types (“extension types”?). For example, I could define an adder interface:
interface Addable<T> {
fun add(a: T, b: T)
}
and then specify that the existing class Int
implements Addable via an extension mechanism using this made up syntax:
override class Int: Addable<Int>
Once you have this, you can write your add function on all types that belong to this type class.
The parallel with extension methods should be obvious: extension methods let you add methods to classes that are already defined, extension types would let you add interfaces to types already defined.
Here is a more complete example. Let’s say we have an interface Monoid:
interface Monoid<T> {
fun zero() : T
fun append(a1: T, a2: T) : T
}
This is a very generic interface used to write a lot of algorithms. Some instances of monoids are (Int, +, 0)
or (Int, *, 1)
. Strings also form a monoid under appending and with the zero element being the empty string.
Let’s say we are using a library defining such an interface and along with it, a lot of useful algorithms based on monoids. In my own application, I am manipulating strings and I’d like to use the algorithms found in this library on them. Unfortunately, the standard String
class is not a monoid (obviously, since it doesn’t know anything about this library).
How can we make String
into a monoid so we can use these algorithms?
First, we add these functions to String
as extension functions:
fun String.zero() = ""
fun String.append(a1: String, a2: String) = a1 + a2
Next, we tell the compiler that String
is now a valid Monoid
using my imaginary syntax:
// Not valid Kotlin (yet!)
override class String: Monoid<String>
From this point on, any function that works on a Monoid
works on a String
.
Wondering if such an approach would be feasible for future versions of Kotlin…