Thread
#arrow-meta
    b

    Ben Woodworth

    1 year ago
    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:
    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
    }
    raulraja

    raulraja

    1 year ago
    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:
    val x: NumberExtensions<Int> = 1 // desugars to 1.extensions()
    b

    Ben Woodworth

    1 year ago
    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.