I've been playing around a ton with type proofs, a...
# arrow-meta
b
I've been playing around a ton with type proofs, and I'm super excited with all the possibilities! 🙂 I'm wondering, is it currently possible to do anything like KEEP-87, for something like extension interfaces? For example:
Copy code
interface NumberExtensions<T> {
    fun T.squared(): T
}

@Given
object IntExtensions : NumberExtensions<Int> {
    override fun Int.squared(): Int = this * this
}

class MyClass(
    /*with*/ val intExtensions: NumberExtensions<Int> = given, // Something like KEEP-87's 'with'
) /*: NumberExtensions<Int> by intExtensions*/ {               // Without needing to delegate like this
    fun printTwoSquared(): Unit =
        println(2.squared()) // Unresolved reference: squared
}
r
Hi Ben! Given is used in meta and will serve the feature of coherent implicit injection or DI. It will not automatically nest scopes of
.run
as Kotlin may bring multiple receivers and it’s a more idiomatic way to deal with that problem in your particular use case. What meta brings for actual syntax projections is
@Coercion
and
@Extension
which automatically project syntax between types. Your example with
@Extension
may look like this.
As you can see this is way more powerful since the syntax is available globally without imports just because @Extension is declared and this new axiom is available to the compiler.
If you were using
Coercion
instead of
Extension
it would be the same but you can also do:
Copy code
val x: NumberExtensions<Int> = 1 // desugars to 1.extensions()
b
Yep! I played around with
@Extension
and
@Coercion
a bunch too, and they're definitely very powerful features. For my specific use case though, I'm a bit wary of using wrappers to add functionality. I originally had classes that wrapped types to add functionality like your
NumberExtensions
class (which would've worked perfectly with
@Extension
), but I ran into performance issues with that, since at times there were tens of thousands of instances to be instantiated each second. I switched to using a typeclass interface with extension members (like my
NumberExtensions
interface), so only one instance needs to be created, and that improved performance significantly for me. I think something like a
@With
annotation to bring the extension members into scope would work really well in my current code. The interface delegation to bring members into scope is working well for me, though it does add/expose unnecessary class members. Here's an example of my old code, and here's the refactored current code. I'm not sure that my current code is the best approach, but I am still wary of creating unnecessary wrappers because of the performance problems I had, especially when one instance to add functionality could suffice.