[HN Gopher] Decoding JSON sum types in Go without panicking
___________________________________________________________________
Decoding JSON sum types in Go without panicking
Author : misonic
Score : 29 points
Date : 2025-03-16 03:32 UTC (3 days ago)
(HTM) web link (nicolashery.com)
(TXT) w3m dump (nicolashery.com)
| reactordev wrote:
| Cool but all you really needed to do was fix the contract between
| NewActionDeleteObject's struct creation and the switch statements
| result = print. What's really crazy is you can create anonymous
| structs to unmarshal json without having to fully flesh out data
| models thanks to its "we'll only map the fields we see in the
| struct" approach. Mapstructure takes this even further with
| squash. In the end, the type checker missed the error because it
| was user error by contract and that, due to lack of validation
| that the actions were constructed properly, resulted in a rabbit
| hole debugging session that ended with an excellent blog post
| about the gotchas of unmarshaling.
| hinkley wrote:
| > human error
|
| Humans suck at formalisms.
|
| When XML was the 'sane choice' I grew to hate it, until I met a
| person who introduced me to XMLSpy. It has a mode where instead
| of trying to define the schema you offer it example documents
| and it offers you a schema that seems to satisfy your examples,
| at which point you can either switch to manual or provide more
| examples. He was right, it did make me hate XML a lot less.
|
| At least until the next job when they wouldn't pay for it.
| shabbyrobe wrote:
| IME this is a longstanding pain point with Go. There's an attempt
| to propose an encoding/json/v2 package [1] being kicked around at
| the moment [2], spawned from a discussion [3].
|
| This at least seems to improve the situation of marshalling
| to/from an interface directly slightly by providing the ability
| to pass custom Unmarshalers for a specific type (via
| json.WithUnmarshalers and json.UnmarshalFunc) to the Unmarshal
| functions, but it appears to still have the inefficient double-
| decode problem. Or I just haven't found a decent way around it
| yet.
|
| Looks like they're intentionally punting on a first class
| solution until (if) the language gets some sort of sum type, but
| I still think the second-class solution could do a bit more to
| make this extremely common use-case more convenient. Pretty much
| every serious production Go app I've worked on in the last 10
| years or so has had some horrible coping strategy for the "map a
| field-discriminated object to/from implementations of an
| interface" gap, often involving some sort of double-unmarshal.
|
| Quote from the proposal [1]:
|
| > _First-class support for union types: It is common for the type
| of a particular JSON value to be dynamically changed based on
| context. This is difficult to support in Go as the equivalent of
| a dynamic value is a Go interface. When unmarshaling, there is no
| way in Go reflection to enumerate the set of possible Go types
| that can be stored in a Go interface in order to choose the right
| type to automatically unmarshal a dynamic JSON value. Support for
| such use cases is deferred until better Go language support
| exists._ [1]: https://pkg.go.dev/github.com/go-
| json-experiment/json [2]:
| https://github.com/golang/go/issues/71497 [3]:
| https://github.com/golang/go/discussions/63397
| 0x696C6961 wrote:
| Last time I checked, the json/v2 package fixed the double
| decode problem by passing the decoder into the unmarshaling
| callback.
| shabbyrobe wrote:
| That's not what I found in my own experiments, I still had to
| unmarshal once inside the callback to get the `type` field
| out, then again once I knew what the type was. Do you have an
| example handy?
| byrnedo wrote:
| Pulled my hair out about doing this all over the place when
| integrating with a node api, ended up writing
| https://github.com/byrnedo/pjson. Feels like this should be
| covered as a more first class thing in go.
| nasretdinov wrote:
| BTW double unmarshalling (and double marshalling) can be quite
| slow, so to speed up determining the object type you can extract
| the type field e.g. by using gjson
| (https://github.com/tidwall/gjson). It can be easily 10x faster
| for this kind of scenario
| hesus_ruiz wrote:
| Reading the article I got the same conclusion as every time I
| approach sum types: they are ONLY useful for addressing malformed
| JSON structs of hacking BAD data structure/logic design, at least
| for most business applications (for system-level programs my
| reasoning is different).
|
| The example JSON in the article, even if it may be common, is
| broken and I would not accept such design, because an action on
| an object must require the action AND the object.
|
| For many year, I have advised companies developing business
| applications to avoid programming constructs (like sum types)
| which are very far from what a business man would understand
| (think of a business form in paper for the first example in the
| article). And the results are good, making the business logic in
| the program as similar as possible to the business logic in terms
| of business people.
| akpa1 wrote:
| Interesting to see V mentioned here. Is it still the chaotic mess
| of a language that'll never be like it was a few years ago?
___________________________________________________________________
(page generated 2025-03-19 23:00 UTC)