logoalt Hacker News

taylorallredyesterday at 5:00 PM2 repliesview on HN

Not speaking for all Go programmers, but I think there is a lot of merit in the idea of "making zero a meaningful value". Zero Is Initialization (ZII) is a whole philosophy that uses this idea. Also, "nil-punning" in Clojure is worth looking at. Basically, if you make "zero" a valid state for all types (the number 0, an empty array, a null pointer) then you can avoid wrapping values in Option types and design your code for the case where a block of memory is initialized to zero or zeroed out.


Replies

masklinnyesterday at 5:27 PM

Only if you ignore the billion cases where it doesn't work, such that half the standard library explodes if you try to use it with zero values because they make no sense[0], special mention to reflect.Value's

> Panic: call of reflect.Value.IsZero on zero Value

And the "cool" stuff like database/sql's plethora of Null* for every single type it can support. So you're not really avoiding "wrapping values in Option types", you're instead copy/pasting ad-hoc ones all over, and have to deal with zero values in places where they have no reason to be, forced upon you by the language.

And then of course it looks even worse because... not having universal default values doesn't preclude having opt-in default values. So when that's useful and sensible your type gets a default value, and when it's not it doesn't, and that avoids having to add a check in every single method so your code doesn't go off the rail when it encounters a nonsensical zero value.

[0] or even when you might think it does, like a nil Logger or Handler

show 1 reply
mh2266yesterday at 5:43 PM

I mean, yeah, you can avoid wrapping things that are optional in Option, but that doesn't make that the result is semantically meaningful. If you have a User struct with "age: 0" does that mean:

1. The user being referred to is a newborn, or:

2. Some other code, locally or on a server you're reading a response from, broke something and forgot to set the age field.

It's not just Rust that gets this (in my opinion) right, Kotlin and Swift also do this well at both a language and serialization library (kotlinx-serialization and Codable) level, but this quote from this article comparing Go and Rust is generally how I think about it:

> If you’re looking to reduce the whole discourse to “X vs Y”, let it be “serde vs crossing your fingers and hoping user input is well-formed”. It is one of the better reductions of the problem: it really is “specifying behavior that should be allowed (and rejecting everything else)” vs “manually checking that everything is fine in a thousand tiny steps”, which inevitably results in missed combinations because the human brain is not designed to hold graphs that big.

https://fasterthanli.me/articles/i-want-off-mr-golangs-wild-...

Basically, if you do not want it to be wrapped in Option then you should either:

1. explicitly specify a default—which can, but doesn't have to be 0.

2. fail immediately (as this article explains) when trying to parse some data that does not have that field set.

and if you do want an Option, you just need to be explicit about that.