> “Numbers are just numbers, you’ll never see 0x80ULL in a .go source file”.
Yet almost immediately afterward, we see the expression:
const uintSize = 32 << (^uint(0) >> 32 & 1)
How is `uint(0)` not just `0u` by another name? And doesn't this code snippet unnecessarily depend on specifically 32-bit and 64-bit architectures? As opposed to something like Rust's `mem::size_of::<T>()` which is both constant-time and also will "just work" on any conceivable architecture past and present?
It's just more golang hype that people read without questioning. int and uint are just one of the many golang mistakes (ironically, another one is mentioned in the article: the way time is defined).
Finally, just repeating that "golang consts are powerful" doesn't make them so.
>We can’t use unsafe.SizeOf as it is not a constant expression
I'm not sure why Dave claims this, since the docstring of unsafe.Sizeof says, "The return value of Sizeof is a Go constant," and this can be trivially verified: https://play.golang.org/p/OvShLD4KLKY
And this turns out to be rather useful in combination with unsafe.Sizeof, since you can use it to write compile-time assertions about the size of your types.
> you’ll see how constant expressions are used to set up complex invariants based on the word size of the machine the code is compiled on.
It's a minor detail but this definitely should be "compiled for" instead of "compiled on", cross-compilation would not work correctly otherwise.
Aside from that I'm not sure if using extra types and constants to prevent stderr etc from being modified is an improvement. Sure you could maybe cause a race condition by changing it in the middle of writing, but how often are new programmers changing stderr at all? What's probably more common is setting it once at the beginning of the program, for example to redirect stderr to logcat on Android. And this change doesn't fix bugs in any legitimate uses, it simply makes them impossible. So I'm not sure who benefits, people who are modifying stderr in a buggy way, but had no reason to do so at all and just didn't realize it?
Same thing with sentinel values. Does any major Go program work by reassigning io.EOF? Has anyone done it by accident ever?
Generally, I don't think the threat model should be a willfully malicious programmer trying to cause problems, or at least it's not a useful model for Go since it's already totally inadequate for dealing with that scenario at a language level.
Rather than what's theoretically possible I think it would be better to focus on what mistakes are commonly made (or have especially severe consequences like security vulnerabilities) and only add program/language complexity where a cost/benefit analysis shows a strong case. That's not to say there isn't one here but I'm unconvinced by the provided examples or personal Go experience.
> Because, by definition, sentinel errors are exported public variables, any code that imports, for example, the io package could change the value of io.EOF.
I haven't tried Go but this already makes it look... dubious.
I wonder why this hasn't been implemented in the standard library yet. People have been doing this for at least 3 years, and the benefits Cheney listed are real.
Another Go constant feature I would love is pure function compile time initialization. It will never happen, but I can dream.
> “Numbers are just numbers, you’ll never see 0x80ULL in a .go source file”.
Yet almost immediately afterward, we see the expression:
How is `uint(0)` not just `0u` by another name? And doesn't this code snippet unnecessarily depend on specifically 32-bit and 64-bit architectures? As opposed to something like Rust's `mem::size_of::<T>()` which is both constant-time and also will "just work" on any conceivable architecture past and present?