Hacker News new | ask | show | jobs
by radlad 1652 days ago
As someone who's been writing Go full-time for only about 8 months now, I've repeatedly been frustrated with the lack of generics while building web APIs. For example, the Go GraphQL ecosystem is a bit of a disaster full of type unsafe code and use of reflection or code generation to support simple things like "a resolver that returns FooResult" vs. "a resolver that returns BarResult."

Here's a fun one I stumbled on: How do you implement a PUT endpoint where a missing JSON value is treated different than a null JSON value? This ends up being very difficult and requires a boilerplate wrapper type for every single type you might accept. It's even worse when you start accepting slices or maps, or slices of maps...

These are areas where generics will help me a lot.

2 comments

This is because JSON and GraphQL are hot garbage. You may as well have written:

> How do I disable static typing for this statically typed language?

I have sympathy for your struggles -- I've been there. But fundamentally this always ends up being a problem of putting a square peg into a round hole.

I don't expect most folks to agree with this take, but I have the utmost faith it'll age well.

If you don't believe me now, set a reminder for ten years and see how we feel about JSON and GraphQL.

You're missing the point: even if JSON and GraphQL were better, untrusted data is always "untyped". Something has to parse the raw representation until proper data types the type system can understand.

Ideally this is all transparent, and programmers can stop wasting their lives reimplementing this stuff again and again and again, but even if programmers don't waste their time reimplementing it, computers will spend a decent amount of time running it, at least where there is more than one process / machine / whatever in question and therefore untrusted boundaries.

I don't follow. Writing a parser doesn't require generics. I've written hundreds of parsers. You can even use a generator like protoc to provide you read/write code that returns/uses concrete, static types.

What on earth does dealing with untrusted inputs have to do with anything?

I wasn't primary talking about generics, I would responding to

> You may as well have written:

> > How do I disable static typing for this statically typed language?

and so just talking about parsing and static type checking.

As it turns out, generics do help immensely if one wants to use so-called "parser combinators".

GraphQL is typed.
> How do you implement a PUT endpoint where a missing JSON value is treated different than a null JSON value?

Tbf that’s a pain in the ass everywhere unless you’re reifying it as a map (so manipulating a json dom).

Iirc in rust the “complete” way to do this for a struct (as opposed to a map) with serde require two options and a bespoke deserializer.

It's much easier to do in dynamically typed languages or by using maps - agreed. Unfortunately we have other design decisions that force us into using structs for deserialization on this endpoint (part of our validation strategy.)

The Go answer is a struct that contains an IsDefined boolean (i.e. your first option), and a pointer-to-value (i.e. your second option.)

This is fine if you need it, but having to write this same logic over and over again for every type gets old... especially if your validators are tied to your types (i.e. a type per field.)

> Unfortunately we have other design decisions that force us into using structs for deserialization on this endpoint (part of our validation strategy.)

Oh I’m not blaming you, sorry if it came across that way. I’m aware of the issue because i’ve been hit by the exact same (hence having been made aware of the rust workaround), can’t say I was a happy camper.