7 ms·
This is the mess a language lands on when it conflates optionality (a semantic concept) with references/pointers (purely a machine concept). In Go, the requirem
by diarrhea 3mo ago
This is the mess a language lands on when it conflates optionality (a semantic concept) with references/pointers (purely a machine concept). In Go, the requirement "need (non-optional) a reference to an object" is simply not expressible. This is a solved problem in other languages, for example `&T` vs. `Option<&T>` in Rust.
- throwa356262 3mo agoWhat the article said applies to Rust ref vs ref-option too.
- tialaramex 3mo agoNot really. It's possible to write this mistake but it's pretty obviously a bad idea, I've never seen someone do this and need correcting. Edited to expand: Sometimes it feels reasonable to have a construction function which returns Option<Goose> rather than Goose because you might be OK with getting back None, for example if you want to make a NonZeroU8 the function to do that will of course give you back Option<NonZeroU8> because you might give it a zero and that's er... not nonzero. But I've never seen people go oh, OK, I guess i'll scatter all my checks throughout the rest of my software and just pass Option<NonZeroU8> everywhere even though I need a NonZeroU8. Rust's shape encourages them to check once during creation like this article suggests.
- Groxx 3mo agoDon't forget mutability! Go throws that on top too.
- Animats 3mo agoIn C++, that distinction supposedly exists. References should never be null, while pointers can be. But there's no enforcement. int& ref = *ptr; ought to generate a panic for a null pointer. But it doesn't. They were so close to getting it right.
- PoignardAzur 3mo agoFor the longest time I thought this line would lead to a crash just because it seemed so obvious. So close indeed.
- FartyMcFarter 3mo ago> They were so close to getting it right. The philosophy of C++ is to not introduce unnecessary overhead, and to trust the programmer. This design choice is prevalent throughout the language. They were never going to make an exception, especially for something as prevalently used as references. There are countless examples of this "no unnecessary overhead and/or trust the programmer" choice: - primitive types and standard containers are not thread safe - it's up to the programmer to know this and use them accordingly. - std::unique_ptr lets you grab the underlying raw pointer, in which case it's no longer a "unique_ptr". But there are cases in which it's useful to do this (e.g. interfacing with C code), so they let you do it, and trust that you do it in a safe way. They could have made unique_ptr not support this, but then it would be less useful (or force you into copying data unnecessarily to call an API that requires a raw pointer). > But there's no enforcement. There's no strict enforcement, but it is undefined behaviour, so compilers can randomly choose to act as if it's enforced and simply crash your program or make it act weirdly.
- VorpalWay 3mo ago> primitive types and standard containers are not thread safe - it's up to the programmer to know this and use them accordingly. Which (sort of) makes sense: most types should not be used across threads. Having everything use atomics/mutexes under the hood would have significant overhead. However, the problem is that the language doesn't then protect you against using these across threads by mistake, this is one of the things that I really like about Rust. Funnily enough, shared_ptr in C++ is thread safe (for the reference count at least), leading to pointless overhead when not used between threads. Rust has both thread safe and non-thread safe versions (Arc and Rc respectively), and it will error if you try to send an Rc to another thread.
- tialaramex 3mo ago
- poly2it 3mo agoIt's really difficult to view Go as a serious language when fundamental design decisions such as this one have seemingly been glossed over. It's in a precarious spot, on the one hand cushioning the C it wants to resemble, but on the other hand not yielding any capable tools or abstractions which could otherwise be unlocked via the safe architecture. Go developers seem uninterested in language design.
- the_gipsy 3mo agoIt's not that it has been glossed over, or was a mistake. It's a tradeoff in favor of simplicity (and compiler / tooling speed). It is difficult to view Go as a serious language because it fails to acknowledge these decisions, repeatedly. You can't really trust the language in that sense.
- 5701652400 3mo agoit does not resolve the problem. you would need to check "is this value optional?" and unpacking everywhere. this is what this article saying. you can do unpacking/nil-checks at the root or later when it happened. with rust you have 2x more ways to shoot yourself in the foot.
- BoardsOfCanada 3mo agoObviously, in his example it would be RateLimiter not Option<RateLimiter>, so no check necessary.
- 5701652400 3mo agoyou still need to unpack that option somewhere.
- Someone 3mo ago_If_ you start out with an optional, and even then only once in the code path.
- guilhas 3mo agoI think the author can propagate RateLimiter instead of *RateLimiter, making it exactly the same
- diarrhea 3mo agoNo, because RateLimiter is then copied on passing it around (pass by value). That is problematic for two reasons: it might be a large type, so copying might be expensive. Second, more likely, it might violate invariants in your domain. For a rate limiter, this might mean accidentally copying around some internal state like a mutex, which then exists n times instead of 1 time, which can represent a problem (e.g. if you want to internally limit whole-app concurrency toward Redis).
- guilhas 3mo ago
- tptacek 3mo agoThis is the most boring argument in computer science. It's like arguing about whether a language should have "goto" or not. There is no new ground to tread here. Most mainstream languages have null references. An entire cinematic universe of languages have been built from the premise that you should not have null references. This is a fundamental rift in programming language theory, and the very best you can do on HN, at least on stories where that rift is not the main point of the article, is to restate it poorly. Seriously, Tony Hoare dropped the mic on these arguments back in 1965. You have to move forward in these discussions on the premise that everybody already gets this very basic, very old PLT argument. Just like if you had somehow managed to find a way to do a spaces versus tabs complaint in a story about (I don't know) Typescript, you will reliably generate sprawling threads by bringing this stuff up on any thread about a language with null references. It's easy for everybody to have an opinion here! Everybody knows the issue! Not everybody agrees! But you aren't doing any good for the thread itself; you're just jamming it.
- ignoramous 3mo ago> Seriously, Tony Hoare dropped the mic on these arguments back in 1965. You have to move forward in these discussions on the premise that everybody already gets this very basic, very old PLT argument. cf. https://news.ycombinator.com/item?id=12427069 https://news.ycombinator.com/item?id=12427069
- zbentley 3mo agoI think you’re arguing against a point that GP didn’t make. Optionality and empty/uninitialized references can both be encoded in a type system, or one, or the other. I didn’t interpret GP as arguing for or against null or otherwise rehashing what you correctly identify as one of the oldest intractable arguments in programming. The sibling comments not so much.
- diarrhea 3mo agoYes, my point was not related to null. For all I care you can have `&T` and `Option<&T>` in your language, but allow `&T` to be null. In Rust, that would be `Option<*const T>`. Is that useful? I don't know. But it still separates the two orthogonal concepts. Go conflates them, rolling them into one, permanently removing useful expressivity.
- misiek08 3mo agoI like using Go for many reasons, but exactly this one is making me sad every time. I can’t accept interface and be sure it’s non-nil at the same time. I think this is a flaw and it’s just a shame.