Live data from Hacker News

Excessive nil pointer checks in Go

konradreiche.com

61–70 of 116 posts

Re: Excessive nil pointer checks in Go

#62

I could have forgiven nil checks, but nil checks on interfaces elevated nils to a whole new level, which is annoying, but I do get where they were going with this: you should never nil check an interface. After all,an interface could be valid for a nil value. There are ways to decently write go and not deal with nil, but as usual, linters defaults makes it impossible and you have to fight with your team before they w…

You are approaching the issue but from the other direction :) It is indeed subtle. It could be solvable though if someone wanted to change the current behavior, in a forward compatible way.

Hint: "Don't use pointers at all" is the requirement that you would have to relax. That means that you cannot know whether a pointer is safe or not to be used from within an interface.

Conservatively, that means that every nil pointer in interfaces are unsafe.

Which means we should either have a way to check for nil pointers (typed or untyped) in interfaces or assert that an interface value cannot contain a nil pointer. (requires definite assignment analysis)

Actually have implemented the nil checking migration part as a POC but seems that it requires the assertion part to be tractable... That is a bit more work.

Re: Excessive nil pointer checks in Go

#63
post #56
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.

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

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

Re: Excessive nil pointer checks in Go

#64
post #54
post #34

Go is a very unique language in that it is the only language designed to make you understand the frustration of online dating. First, seduction, and then as it reveals how little it cares about you, eventual disappointment.

[flagged]

A bit much.

Re: Excessive nil pointer checks in Go

#65

I could have forgiven nil checks, but nil checks on interfaces elevated nils to a whole new level, which is annoying, but I do get where they were going with this: you should never nil check an interface. After all,an interface could be valid for a nil value. There are ways to decently write go and not deal with nil, but as usual, linters defaults makes it impossible and you have to fight with your team before they w…

This suggestion fails for values that can be null, need to be mutable or need references from multiple places etc – it's not "just performance penalty". Go has a problem, "just remember to always do X, never Y" patterns can't be guaranteed across all libraries you use, can't be enforced, can be violated for good reasons, other patterns and as a mistake etc etc. Shame because otherwise it's a great language, but some…

> They need Go 2 with T and ?T - that would be nice language to use.

Zig has basically been this to me. As a developer, writing Zig feels a lot like writing Go, except with basically all of the pain points addressed.

- Zig has different pointer types for different things. The default pointer type points to exactly one value. It also has an optional pointer type as described. Arrays and slices are also pointers of sorts, and a graph in this post[0] does a good job describing the relationships between N element pointer types.

- Zig has a built-in error type that is able to carry stack trace information.

- Zig has a syntactic shorthand for the common `if err != nil { return err}` pattern: the `try` keyword.

- Zig doesn't impose a garbage collected runtime.

- defer can handle arbitrary expressions in Zig. They do not need to be wrapped in a closure or a function call.

- The frankly weird interface system in Go is replaced with one of the more sane metaprogramming systems (I would argue that comptime is the most sane metaprogramming system in any C-like language).

Other than that, Zig and Go are very similar. They both use repos for modules. They have roughly the same concurrency semantics. They have the same allocate+defer deallocate pattern (though more flexible in Zig, also due to scope bound vs function bound). They both treat errors as values. They both disallow things like operator overloading. They both have built in testing systems.

Zig makes breaking changes in ways that Go doesn't anymore, but the breaking changes are always very thoughtful, and are clearly converging on something that is more flexible than Go (both in expressiveness, and in portability) but with a very similar mental model for developers.

[0] https://ziggit.dev/t/array-and-slice-address-relationship/14...

Re: Excessive nil pointer checks in Go

#66
post #56

Earlier quoted context omitted.

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

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

Yes, my point was not related to null. For all I care you can have `&T` and `Option` in your language, but allow `&T` to be null. In Rust, that would be `Option`. 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.

Re: Excessive nil pointer checks in Go

#68
The design of error handling in Go is interesting because they wanted to force people to actually handle errors by returning them as values, but then you as the programmer have to decide whether an error should be returned or a panic should be used.

It reminds me of the original intention of checked exceptions in Java: checked exceptions are for things you force the caller to handle, unchecked exceptions are for "you the programmer messed up". In reality checked exceptions are pretty unpopular and can't be used in many situations, so people fall back to unchecked exceptions.

If we equate unchecked exceptions with panics in Go, falling back to panics would be an anti-pattern in many cases.

NPEs in Java have become rarer and rarer recently with the introduction of records (to easily create immutable classes, which are easier to validate for null against). Plus JSpecify annotations get you null denotation that's almost as good as Kotlin's. Combine that with NullAway are you have compile time null safety. Go has nilaway [0]. One interesting thing about nilaway is that you don't null-annotate your code, it just detects nilness when you run nilaway. That makes nilaway a decent tool to get feedback right away, but it doesn't force you to document the intention behind parameters and fields for whether they are nullable or not, which I would argue is one of the advantages to null-annotating Java code with JSpecify.

[0] https://github.com/uber-go/nilaway

Re: Excessive nil pointer checks in Go

#70

The design of error handling in Go is interesting because they wanted to force people to actually handle errors by returning them as values, but then you as the programmer have to decide whether an error should be returned or a panic should be used. It reminds me of the original intention of checked exceptions in Java: checked exceptions are for things you force the caller to handle, unchecked exceptions are for "you…

> NPEs in Java have become rarer and rarer recently with the introduction of records

While this is true, I think it goes back farther than that. NPEs became rarer since java.util.Optional and people taking the time to use JSR 305 nullability annotations. I do this on regular basis and haven’t seen NPEs in my work for ages now.

Because I’ve taken on projects with large Java codebases often written by people with poor code-design skills, I can say the single most frequent NPE offender I’ve seen was method bodies wrapped in: try { } catch {} return null.

Modern language features like Kotlin’s non-null fields are nice, but I hold self-discipline just as important.

Post reply on HN