News for hackers. Stuff that matters.
Re:A New Go API for JSON by thayne on Wednesday November 04, 2026 @02:14PM (#50370186)
It could be if go had a more powerful type system.
Re:A New Go API for JSON by hnlmorg on Wednesday November 04, 2026 @02:19PM (#50370265)
This isn’t a type system problem. It’s a data origin problem. Ie it could be any random JSON blob a user entered. The compiler doesn’t know this ahead of time.

If you wanted type safety with JSON in Go then don’t use the marshal interface. Period.

Re:A New Go API for JSON by thayne on Wednesday November 04, 2026 @02:51PM (#50370622)
For unmarshalling, but the original complaint was about marshalling. And for that the type system could help if the marshal API only allowed you to marshal objects of types that supported marshalling.
Re:A New Go API for JSON by hnlmorg on Wednesday November 04, 2026 @03:05PM (#50370779)
I’d already addressed that when I said the marshal API is an interface that’s meant to be reusable across generalise use cases. it can be used for a variety of data formats and not just JSON.

Go has this concept baked into the language. For example read and write interfaces so you can write data to an endpoint without having to worry about whether it’s a file system object, TCP/UDP socket, gzip achieve, and a plethora of other options too.

It’s a nice convenience feature and makes up considerably for the restrictions that the Go type system places.

And if you need higher performance code, or compile time safety, or have any other constraints that limit your ability to use these generalised interfaces, then you can use different APIs from the Go standard library to achieve the same thing.

You don’t need to call json.Marshal() if you don’t want to. It’s an option, but it’s just one API into the JSON toolbox.

Re:A New Go API for JSON by thayne on Wednesday November 04, 2026 @04:07PM (#50371540)
First of all, the json2 Marshall API is json specific.

Secondly, other languages like rust, haskell, scala, etc. Have json APIs that are typesafe and give you compile time errors if you try to use a type that doesn't support (de) serialization . In the case of rust at least, the API is also general and can be used for other data types as well.

Even in go, you could have some more type safety if Marshall took an interface (such as MarshallerTo) rather than `any`. Although then you have the problem of how you implement that interface. So I guess you probably want some kind of "derive" functionality, or macros that can approximate it for a convenient and type-safe API.

P.S. gophers like to talk about how explicit being better than implicit, but using reflection for marshalling is very implicit.

Re:A New Go API for JSON by hnlmorg on Thursday November 05, 2026 @02:11AM (#50376101)
Except it’s not JSON specific. The article literally talks about how their function design was chosen for similarity with the v1 API. And I’d wager that the go team are planning on reusing that function signature for other encoders too. Or at least expecting it to be reused by the wider ecosystem.

If you want type safety then pass a struct to the marshal. Which is actually the idiomatic way to do it anyway. The type safety would be in that.

I’m not going to disagree with you that Gos type system is a rather blunt tool nor that Gos expressiveness is extremely rigid compared to many other popular languages. All of that is completely true. But I don’t agree that the v2 JSON API is a good example of that problem.

Re:A New Go API for JSON by thayne on Thursday November 05, 2026 @01:56PM (#50382917)
> Except it’s not JSON specific.

The function is in the `encoding/json/v2` package. It might have a similar design, and maybe they will use the same function signature for other encoders, but it the functions are very much json specific.

> If you want type safety then pass a struct to the marshal.

But if you use a struct that has a field that can't be marshalled, you don't get a compile error, you get a runtime SemanticError. That's the problem.

Re:A New Go API for JSON by hnlmorg on Thursday November 05, 2026 @04:01PM (#50384410)
> The function is in the `encoding/json/v2` package. It might have a similar design, and maybe they will use the same function signature for other encoders, but it the functions are very much json specific.

But the point you keep missing is that the function signature needs to be encoder agnostic for it to work as an interface.

> But if you use a struct that has a field that can't be marshalled, you don't get a compile error, you get a runtime SemanticError. That's the problem.

And as I said elsewhere, no such fields exist.

Re:A New Go API for JSON by thayne on Friday November 06, 2026 @02:47AM (#50389366)
> But the point you keep missing is that the function signature needs to be encoder agnostic for it to work as an interface.

It's a function, not a method. So it can't be part of an interface.

I suppose you could make an argument for passing it as a function argument to a higher ordered function. But that is kind of an unusual way to use such a function. And isn't a common pattern in go.

> My point here was: if you know you’re creating a struct to pass to the mashaller at compile time, then you’re already going to use JSONAble fields. So it’s not an issue.

Maybe. Maybe not. For a simple struct where all the fields are primitive types sure. But if you have a complicated hierarchy, you might miss that some strict in the hierarchy has a field that can't be marshaled.

Say you are marshaling a struct that contains a struct from a third party library, and it works fine. Then you update to a new version of that library, and that added a new field for a type that doesn't work, say a map[A]string where A is a struct. Your program still compiles fine, but then you get an error at runtime when you try to serialize something that worked before. Hopefully you have tests that catch it.

Re:A New Go API for JSON by hnlmorg on Friday November 06, 2026 @04:00AM (#50389878)
> It's a function, not a method. So it can't be part of an interface.

The mashaller here is a function, yes. But having a consistent signature means you can interchange those marshallers. It’s a trick I use heavily in murex to enable typed pipelines.

And I do this via a pipe interface. So it’s not uncommon to reuse function signatures for interface types (fewer runtime abstractions) while retaining some level of dynamism.

> Say you are marshaling a struct that contains a struct from a third party library, and it works fine. Then you update to a new version of that library, and that added a new field for a type that doesn't work, say a map[A]string where A is a struct.

The first mistake there is to blindly forward an API struct that you don’t control and depend on that for business logic.

Which comes back to my point about if you want type safety then you’d create a struct.

I do take your point that the compiler in smarter languages would catch this. But you’d equally be told not to do this sort of thing on those languages too.

Re:A New Go API for JSON by awesome_dude on Wednesday November 04, 2026 @06:48PM (#50373044)
I'm confused by this - you're saying that a "type system" would address this, even though there are two (incompatible) type systems at play here - Go's and JSON's

Compile time cannot check for runtime values (not even in Rust) - is your position that fields can only be populated at compile time?

Re:A New Go API for JSON by thayne on Wednesday November 04, 2026 @11:32PM (#50375214)
In go, the Marshall and unmarshal functions take `any` for the source or destination. If you use a value of a type that doesn't support marshaling or unmarshalling (say because it contains an unserializable type like a channel, function pointer, etc) then you get a runtime error. Whereas in rust, Haskell, scala, etc. you can get a compile time error if you try to use a type that doesn't support serialization.
Re:A New Go API for JSON by hnlmorg on Thursday November 05, 2026 @02:26AM (#50376191)
You don’t get runtime errors for marshalling pointers to JSON. I actually do this all the time. What you get is the address of the pointer marshalled.

I think the same is true for channels too but I’m not near a computer to check.

Re:A New Go API for JSON by thayne on Thursday November 05, 2026 @01:58PM (#50382945)
> You don’t get runtime errors for marshalling pointers to JSON

https://pkg.go.dev/encoding/json/v2#Marshal says otherwise:

> The Go map key must encode as a JSON string, otherwise this results in a SemanticError

> All other Go types (e.g., complex numbers, channels, and functions) have no default representation and result in a SemanticError.

v1 has the same constraints.

Re:A New Go API for JSON by hnlmorg on Thursday November 05, 2026 @04:06PM (#50384463)
> A Go pointer is encoded as a JSON null if nil, otherwise it is the recursively JSON-encoded representation of the underlying value.

The doc you linked to literally proves me right.

Re:A New Go API for JSON by thayne on Friday November 06, 2026 @02:21AM (#50389219)
That just shows there are pointer values that can be marshaled, not that all such values won't error. If you have a non-nil pointer that points to an object that transitively contains one of the unsupported types, you will get an error.
Re:A New Go API for JSON by hnlmorg on Friday November 06, 2026 @02:39AM (#50389323)
I read that differently. If you have a non-nil pointer then you get the address of the pointer irrespective of what that pointer points too.
Re:A New Go API for JSON by thayne on Friday November 06, 2026 @01:17PM (#50396120)
I'm not sure how you are getting that from "otherwise it is the recursively JSON-encoded representation of the underlying value", but here is a playground example, where using a non-nil pointer to a channel produces an error: https://go.dev/play/p/JXYuGUQ0TLQ