amazon-ion / ion-element-kotlin

IonElement is an immutable in-memory representation of the Ion data format. IonElement's API is idiomatic to Kotlin.
Apache License 2.0
8 stars 8 forks source link

Improve usage of `with*` mutators from Java #53

Closed dlurton closed 2 years ago

dlurton commented 3 years ago

The with* functions in IonElementExtensions.kt work great from Kotlin to create a new value with annotations or metas from an existing IonElement instance, but they are not currently exposed to Java at all due to them being inline and reified. The original intent of making them inline and reified is to reduce some of what trivially appears to be copy-pasta in definitions of IonElement and the derived interfaces such as IntElement, StringElement, etc, but unfortunately this also makes these functions entirely unknown to Java. (It is not even possible to refer to them as static methods, i.e. IonElementExtensions.withMetas.

This task is to explore moving these functions to IonElement and derived interfaces instead. In the derived interfaces, these functions should utilize covariant return types to narrow the return type of these functions.

val intElem: IntElement  = ionInt(42)
val ionElem: IonElement =  intElem

val intElem2: IntElement = intElem.withAnnotations("foo") // return type of IntElement.withAnnotations is IntElement
val ionElem2: IonElement = ionElem.withAnnotations("foo") // return type of IonElement.withAnnotations is IonElement

In other words, if I have an instance of the narrowed IntElement, adding an annotation to it should not widen to IonElement. This avoids the need to re-narrow the type after adding the annotation:

val intElem2: IntElement = intElem.withAnnotations("foo").asAnyElement().asInt()

The calls to .asAnyElement().asInt() are not required because of the covariant return type.