Union type support #682
ThijsBroersen
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
In #679 I implemented a basic string-based union support. Before continuing on implementing other types or merging that one as is, lets have a discussion here on a way forward which will be compatible with these initial api changes.
I think the project needs a design decision on what types to support. In json we have to following types
string | number | object | array | true | false | null
, this is the rawest distinction we can make without any context.When building a codec we need to determine how we are encoding and decoding a type, As long as there is a clear mapping between a Scala type and a json-type the codec should be possible, e.g.
Null | String | Int | Boolean | List[Int]
but having two numerical typesInt | Double | Float
would be troublesome, as we cannot say for sure how the numerical type should be decoded. A Long is mostly encoded as a string, hence aString | Long
would also be a conflicting pair.For things like
List[Int] | List[String]
we can easily find a path by testing a decoding path on the first element. ButList[Double] | List[Float]
would be problematic again.For literal types goes the same:
String | "right"
conflicts. The sender could have sent String("right"). So either it is the primitive type or only literal values for that primitive type.With some macros we can probably check if the union is disjoint from a JS perspective.
The case class / object -> object is a more complex story as soon as there are more than one case class types in the union. Objects then need a discriminator to identify the type of the object.
A simple approach would be to use the name of the case class or object, collect all and validate there are no conflicts. Perhaps use an annotation to override the name if there is a conflict.
Another options would be to use the full package name + class name, this would of course be way more unique but verbose.
Sealed traits follow the same path. All family members must not conflict with names of family members of other families (sealed traits) or case classes. But also here we could use the full name (with package).
Enum-types conflict with String and enum-types cannot overlap unless the enum-values are represented by their full name.
This approach uses discriminators only on objects. Another way would be to just use a discriminator on all union types and wrap values in objects. That way different numeric types can be mixed for example. And extending the union would then be backwards compatible with earlier encoded data. But it would cause some overhead for the cases it is not really necessary. For literal types it could be ugly (two times the same value).
Please share your thoughts on this.
Beta Was this translation helpful? Give feedback.
All reactions