Yes, but the whole point to using abstractions (such as high-level languages) is to separate the context where implementation details are relevant (e.g., when writing a compiler), from the rest of the system, where implementation details don't matter (e.g., when using a compiler).
It's a stunningly difficult and surprisingly low-value proposition to create abstractions that don't leak. That's not the goal anyway: The goal is to leverage abstractions to build things. The implementation details frequently do matter. Even if your abstraction is airtight, it has to run on a real machine. When possible, it's preferable to design abstractions that have a clear implementation in terms of the lower level's abstractions. This way, when something goes wrong - and it will - you can understand and fix it.
The behavior of Go's nil does not make the language any simpler to implement in any meaningful sense. The only thing it affects at the machine level is which cmp instructions are generated.
I won't defend the weird behavior of equality comparisons to nil, that definitely seems wrong. I was mostly just addressing the notion that a language needs a formal specification and must fully abstract the machine to be useful or at least not worthy of ridicule.
> It's a stunningly difficult and surprisingly low-value proposition to create abstractions that don't leak.
Maybe for you. For me, non-leaky abstractions have enormous value. And, while designing non-leaky abstractions requires more effort upfront, in the long run, it requires less effort than plugging leaks in carelessly designed (non)abstractions.
> That's not the goal anyway: The goal is to leverage abstractions to build things.
The goal is to do it efficiently, and creating as few problems as possible for the future.
> The implementation details frequently do matter.
Of course they do matter - for the implementor.
> When possible, it's preferable to design abstractions that have a clear implementation in terms of the lower level's abstractions.
No disagreement here.
> This way, when something goes wrong - and it will - you can understand and fix it.
That's the job of the abstraction's implementor. If that happens to be me, I will fix it. Otherwise I'll just submit a bug report. If that doesn't work, then I'll reimplement the abstraction myself, but by no means will I work around an existing broken implementation.