Live data from Hacker News

Excessive nil pointer checks in Go

konradreiche.com

41–50 of 116 posts

Re: Excessive nil pointer checks in Go

#41
This is exactly what LLMs are really bad at. They don't have the knowledge (and don't ask for) the invariants of the system and write defensive code at every step of the way, which is not just unnecessary, it's bad because if an unexpected state still get into the system, you will never notice and bad data will flow through and makes everything unpredictable.

Re: Excessive nil pointer checks in Go

#42
post #9

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 ` in Rust.

it 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.

> with rust you have 2x more ways to shoot yourself in the foot.

The checking isn't how you shoot yourself in the foot, it's the absence of checking. Rust doesn't allow you to forget to check. This entire class of problems just disappears in Rust.

In this if the code needs a non-null redis client to work you take `RedisClient` not `Option`.

Re: Excessive nil pointer checks in Go

#43
post #14

Earlier quoted context omitted.

In 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.

> 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 sta…

> 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.

Re: Excessive nil pointer checks in Go

#45
post #20

Earlier quoted context omitted.

Fortunately we have type systems to encode many contracts at compile time, including stuff like optionality. Certainly no modern language would still repeat Hoare’s "billion dollar mistake"? Right? …Oh.

It's so bad that here we are in the 21st century and there are even still people who insist it wasn't a mistake e.g.: https://www.gingerbill.org/article/2026/01/02/was-it-really-...

It's quite a delusional take from Bill. Wow. Using non-nullable (a sane language default) pointers in Zig is liberating experience. And it's still as low level as in C but instead of ship-and-pray you could state your intention with a type system.

Re: Excessive nil pointer checks in Go

#46

Earlier quoted context omitted.

You check and unpack once, then the rest of the "positive" codepath can use the reference without fearing null. I fail to see how Rust would offer twice as many ways to shoot yourself in the foot ; this is a rather safe and picky language.

true, "non-nil pointers"/references will help here to avoid nil checks. also true, if you have optional you still need to unpack it somwhere, and your nil checks become unpacking statements. delayed conditionals and delegation to callsites far from offending code (what author says) is still present. and if you also have pointers, then you can do Optional .. and now you have to option unpakcing + nil checks. 2x more p…

If you have an actual pointer type *mut P then Option might be None or it might be Some(null_pointer) or Some(other_pointer) that's not 2x more problems it's just a representation of a more complicated scenario - we may or may not have a pointer and, if we do have a pointer that might be null. We'd presumably have done this because we need to distinguish those cases.

If you actually mean Option> you should write that, now we're saying this is either a non-null pointer or it's nothing. Often though you want Option either a reference or nothing, or you actually did mean a raw pointer *mut P and you're going to handle scenarios where it is null or whatever.

Edited: Fix asterisks

Re: Excessive nil pointer checks in Go

#47
post #14
post #9

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 ` in Rust.

In 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.

No, it ought to generate a compilation error unless the compiler can prove that the pointer isn't null.

... but that only works if you design properly from day one.

Re: Excessive nil pointer checks in Go

#48

Earlier quoted context omitted.

> 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 sta…

> 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 t…

mutable XOR alias is also key here

For a typical type Goose it's fine if two threads can both look at the Goose (via a reference, pointer or whatever), so long as nobody can mutate the Goose. If thread A finds that the Goose is Happy, thread B weighs the Goose and finds it to be Heavy, and thread A again measures the length of the Goose as 860 millimetres this is all fine, it won't matter if (by the vagaries of hardware) the weight is measured before the length or after, there's no difference.

In Rust this is reflected in &Goose, the immutable reference to a Goose, being Send, ie a thing you can give to other threads. The mutable reference &mut Goose is not Send.

Re: Excessive nil pointer checks in Go

#49
To avoid propagating the pointer I would change *RateLimiter to RateLimiter

DecodeRequest can return Request instead of *Request, or error if not valid

Also I would replace `if userID == "" {` with `if err != nil {`. If an object is not loaded successfully returning error I think is more standard

Re: Excessive nil pointer checks in Go

#50

Earlier quoted context omitted.

it 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.

Obviously, in his example it would be RateLimiter not Option , so no check necessary.

I think the author can propagate RateLimiter instead of *RateLimiter, making it exactly the same
Post reply on HN