This is a small multiplatform library dedicated to typed attribute containers inspired by kotlinx-coroutines contexts.
Attribute is a marker interface for an attribute key.
Attributes is a generic immutable container for key-value pairs.
SafeType is a compile-type checked wrapper for KType.
The attribute access is done in the following way:
object MyAttribute: Attribute<Int>
val value: Int? = attributes[MyAttribute]One could also add shortcuts to attribute container for convenience:
class MyContainer: AttributeContainer
val MyContainer.myAttribute: Int? get() = attributes[MyAttribute]While Attributes class itself is a container that could hold any kind of attributes, its parent container (usually AttributeContainer)could expose only specific attributes via extensions.
Attributes is created with a function with the following signature:
fun <O> Attributes(builder: AttributesBuilder<O>.() -> Unit): AttributesAttributeBuilder is a mutable container that exists only during attribute configuration. One could do the following operations with it:
- put values into it via key (new values override existing values with the same key) via
putoperation (prefix or infix notation) - add or remove an element from
SetAttribute
val attributes = Attributes{
put(MyAttribute, 3)
MyAttribute put null
MyAttribute(4)
}The last notation (invoke-based) is added for convenience.
The type-parameter of the builder is used only in compile time to provide more extension points. ForExample one could provide extensions for builder like this:
fun AttributesBuilder<MyContainer>.defaultMyAttribute() = put(MyAttribute, 0)Attributes are immutable, so to modify attributes one needs to copy them. There are several methods to do that like:
withAttribute- create a copy with additional (or overriding) attribute;withFlag- the same for flag (value-less) attribute;withAttributeElement/withoutAttributeElement- add or remove an element from set-valued attribute;plus- compose (overlay) two attributes sets.
Other modifications could be added as extensions.
Generic modifications could be done via
fun <O> Attributes.modified(block: AttributesBuilder<O>.() -> Unit): AttributesPolymorphic attributes (attributes, where value has a type parameter) are more complicated. They could not be used as singleton keys since each key has a different parameter. Users may want to provide a key factory instead of keys themselves so they could organize key caching and avoid creating keys on each access:
class Determinant<T>(type: SafeType<T>) :
PolymorphicAttribute<T>(type),
MatrixAttribute<T>
val <T> MatrixScope<T>.Determinant: Determinant<T> get() = Determinant(type)
with(matrixScope) {
val determinant = matrix[Determinant]
}It is possible to simplify the work with polymorphic attributes by implementing type erasure for type arguments, but it will violate structural equality guarantees. Polymorphic attributes are work in progress and could change in the future.
The Maven coordinates of this project are space.kscience:attributes-kt:0.3.0.
Gradle Kotlin DSL:
repositories {
maven("https://repo.kotlin.link")
mavenCentral()
}
dependencies {
implementation("space.kscience:attributes-kt:0.3.0")
}