I'm pretty sure I already know its not possible in...
# getting-started
d
I'm pretty sure I already know its not possible in Kotlin, but I'll double check here. I want to have a return type dependent on an interface type parameter and function type parameter.
Copy code
interface ExtensibleAwareKey<E</* magic syntax here*/>> {
    fun <B> of(type: KClass<B>): ExtensionKey<E<B>>
}

inline fun <reified B, E</*magicsyntax*/>> ExtensibleAwareKey.of() = of(B::class)

data class TypeDependentKey<B, E>(val type: KClass<B>) : ExtensionKey<E>

// example implementation:
class Describable<E> {

    companion object : ExtensibleAwareKey<Describable</*magic*/>> {
        override fun <B> of(type: KClass<B>): ExtensionKey<Describable<B>> = TypeDependentKey<B, Describable<B>>(type)
    }
}
After some ChatGPT conversation, I guess what I'm asking about is called "higher-kinded types". It doesn't look like kotlin supports it. Also, I typoed
TypeDependentKey
, it should extend
ExtensionKey<E>
. I've edited my original question.
I'm not entirely sure its Functional programming. I'm more familiar with it in TMP with C++.
I reworked it myself. It needs a lot more scaffolding to work correctly, but I did get it to function how I wanted.
👍 1
Extensible.kt
Copy code
interface Extensible {
    fun <E : Any> getExtension(key: ExtensionKey<E>): E?
    fun <E : Any> putExtension(key: ExtensionKey<E>, value: E)
    fun <E : Any> getOrPut(key: ExtensionKey<E>, initializer: () -> E): E
    operator fun contains(key: ExtensionKey<*>): Boolean
    fun remove(key: ExtensionKey<*>)
    fun removeIf(predicate: EntryPredicate)
    fun keepIf(predicate: EntryPredicate) = removeIf(predicate.not())
    fun forEach(visitor: EntryVisitor)
}

operator fun <B : Extensible, E : Any> B.get(key: TypeDependentExtensionKey<B, E>): E? =
    getExtension(key)

operator fun <E : Any> Extensible.get(key: ExtensionKey<E>): E? = getExtension(key)

operator fun <B : Extensible, E : Any> B.set(key: TypeDependentExtensionKey<B, E>, value: E) =
    putExtension(key, value)

operator fun <E : Any> Extensible.set(key: ExtensionKey<E>, value: E) = putExtension(key, value)
TypeDependentExtensionKey.kt
Copy code
open class TypeDependentExtensionKey<B : Extensible, E : Any>(val type: KClass<B>, val equality: Any) :
    ExtensionKey<E> {

    companion object {
        inline operator fun <reified B : Extensible, E : Any> invoke(equality: Any) =
            TypeDependentExtensionKey<B, E>(B::class, equality)
    }

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other !is TypeDependentExtensionKey<*, *>) return false
        return type == other.type && equality == other.equality
    }

    override fun hashCode(): Int {
        var result = type.hashCode()
        result = 31 * result + equality.hashCode()
        return result
    }
}
Describers.kt
Copy code
class Describers<B : Any> internal constructor(
    private val builder: DescribersBuilderImpl<B> = DescribersBuilderImpl(),
) : DescribersBuilder<B> by builder {
    
    companion object {
        inline operator fun <reified B : Extensible> invoke() = TypeDependentExtensionKey<B, Describers<B>>(this)
    }
}
The downside is I have to make a function call instead of simply reference an object:
myExtension[Describers()]
as opposed to
myExtension[Describers]
That's just to distinguish
Describer keys
from
Other extension keys
.
👍 1
So, two "TypeDependentExtensionKey" are only equal if they are the same type of extension, and the same dependent type.
Describer.Companion is the marker for the "kind" of extension.