Closed kspeakman closed 2 years ago
I believe ExternalTag ||| NamedFields ||| UnwrapRecordCases
achieves the encoding you proposed.
Otherwise, if you're willing to use a converter on the object-oriented language side, something like this seems compatible with InternalTag ||| NamedFields ||| UnwrapRecordCases
for a more natural inheritance-based representation. I would be surprised if other languages don't have similar solutions; serializing type hierarchies is a commonly-asked feature.
Apologies as I didn't notice that specific combination. After a bit more tracing through the examples, this does almost exactly what I described. Perhaps even better overall compatibility with inheritance schemes and languages lacking tuple support. Cheers.
Most of the available representations for DUs were patterned after reflection api arguments rather than general utility. It is possible to serialize DUs into object-compatible JSON. Which means that if absolutely necessary, another language without DU support is capable of deserializing the produced JSON into a statically typed object without a special converter. (And it seems no worse for dynamic languages either.) So a DU like this:
Would get serialized like this:
And could be deserialized into a DTO like this:
This isn't an ideal representation of course. It's memory inefficient and fiddly to use. But it will scrape by. And with a small effort, a custom converter can turn the json into shallow inheritance classes (like F#'s internal representation of DUs) or marker interface classes in an obvious way.
I couldn't see a combination of the existing encodings that had similar compatibility. Adjacent doesn't have a helpful direct representation in typed languages (Fields becomes a boxed object array). Most encodings use heterogeneous arrays for case values. These make sense for 2+ item tuples. But are unhelpful for 0 or 1 parameters -- how to make 0- or 1-tuples? or an empty array of what? or extra array wrapper around a single value. That's why I used empty object for no case args. (Using the simple case name string is hard to represent compatibly with other cases that have args, and raises questions with camel casing.) And for 1 arg the unwrapped value makes the most sense -- don't force the consumer to index into an array when it will only ever have 1 value.
I'm probably out on a limb with this -- I fully expect I'll have to find/adapt a converter if I ever switch to STJ. So I hope you will at least find this perspective interesting. Best wishes.