I think in both cases, they are allowing pragmatism to win out over correctness. The underlying systems that Dart & Go try to interface with embrace NULL with a kind of oblivious joy that can't be replicated.
I find the idea that optionals aren't pragmatic pretty bizarre. Of all the features that "advanced" type systems give you, optionals are some of the most straightforward. I still haven't heard a convincing argument for why they should not be in Go (e.g., someone pointed out that all types in Go have a default value, but there is a very obvious candidate for a default value for optionals--None; "in practice these issues don't come up"--doesn't that just mean people don't use null much? Why allow it to inhabit every type, then?).
Anyway, neither Dart nor Go is particularly "close to the hardware" as they both have fairly substantial runtimes. We're not talking about a macro assembler here, we're talking about a typed programming language. What the compiler does under the hood is largely irrelevant in any language that doesn't make a distinction between register, stack, and heap allocation.
It’s an example of the “New Jersey approach” to programming language design.
> Simplicity-the design must be simple, both in implementation and interface. It is more important for the implementation to be simple than the interface. Simplicity is the most important consideration in a design.
If the underlying interface (JavaScript or POSIX as the case may be) is using NULL's up the wazoo, then you need a way to represent that. You can try to represent it as optionals, but that creates impedance, which ultimately may cost you more complexity (and performance).
It doesn't have to cost performance (not even compiler performance!) or create impedance. You just represent the None variant as null in the compiled output. I realize this sounds suspiciously easy and it seems like there must be something I'm glossing over, but there honestly isn't, as long as you never introduce null to your own language in the first place. Once you've done that, though, it gets harder, because you have to differentiate between Some(null) and None, which means they can't both be compiled to null. But this is a completely self-imposed problem; it is not an issue when you create a language from scratch, only if you want to retrofit optionals onto an existing language.
> I realize this sounds suspiciously easy and it seems like there must be something I'm glossing over, but there honestly isn't, as long as you never introduce null to your own language in the first place.
Yeah, having done this before, it isn't that easy. You basically have to map NULL to something else, and if that mapping is so direct and straight forward, you actually haven't improved your engineering one bit.
It is literally that easy. This is how it is done in Rust, for instance. You have improved your engineering by (1) requiring exhaustive match on anything that is potentially null, and (2) eliminating the need to check for null anywhere else. I don't understand why people take it as an article of faith that this must be difficult. In fact, the sheer simplicity of it is why I believe it should be in Go, and am confused about why it is not.