[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)