Hacker News new | ask | show | jobs
by nemothekid 2193 days ago
>I disagree about nil as well; I think Go's zero value approach is useful, and basically impossible without nil (it wasn't necessary in my code, but I may want to instantiate an ApiResponse object without a data structure ready to be passed in).

I like your solution to my imaginary problem, but I am going to counter this one. Now I'm salty because nil interface[1] actually bit me once and cost me. Go's zero value approach also exists in Rust, but is type safe. Basically every primitive type, and Option<T> have zero values. Any struct that is made up of those values can also safely have zero values. Then for those that don't, you can implement your own zero values. This is called Default in Rust. Go's zero value approach is perfectly possible, and arguable better without nil. And even then, the number of times I've seen a service crash because someone "forgot" to initialize a nullable type, and passed it to a function that then exploded isn't an issue I should deal with in 2020.

[1] https://medium.com/@glucn/golang-an-interface-holding-a-nil-...

2 comments

First of all, interfaces are not nil if they point to a nil value for the same reason a * * T is not nil if the * T is nil. That is the correct decision. You can not call a function on a nil interface, but you can call a function on an interface which is not nil, but where the value of the type is nil[1].

As for your proposal, there are some issues with it: not all structures have a sane default for all not optional, nilable parameters. What is the default underlying reader for a bufio.Reader? A reader which returns zero bytes? Certainly that would be more confusing to debug than a simple panic, which is what we have now [2]. There's also the fact that a zero value is just a value with all the bytes zeroed and allocating an object via language means (new) never allocates more than the size of the object and doesn't do computation.

But I guess the main point would be that I simply do not have a problem programming with nil-able types. Failing to initialize in Go means writing var a *T as opposed to a := &T{} or a := NewT(), which seems like an odd mistake to make - or forgetting to initialize a member of a struct in the NewT() function. Fundamentally, I do not want to spend hours of my life dealing with safeguards which are protecting me from a few minutes of debugging.

But hey, that's just me. Go isn't Rust and Rust isn't Go and that's a good thing.

[1]: https://play.golang.org/p/L7iy9YBC55c [2]: https://play.golang.org/p/Vgv73KhegKI

> not all structures have a sane default for all not optional, nilable parameters. What is the default underlying reader for a bufio.Reader?

I think you're actually agreeing with nemothekid here, what you're saying is that there is no sensible default value for a bufio.Reader. In Rust terminology, that would mean bufio.Reader would not implement the Default trait. Types need to explicitly implement the Default trait, so only types where that makes sense implement it.

> I simply do not have a problem programming with nil-able types

Yes, that's going to make a big difference to how you feel about features that reduce the chance of errors like that. I'd hazard a guess that in C# the most common exception that is thrown is the NullReferenceException, after a quick search[1] it looks like NullPointerException is a good bet for the most common exception in Java. Most of those IlligalArgumentExceptions are probably from null checks too.

> Fundamentally, I do not want to spend hours of my life dealing with safeguards which are protecting me from a few minutes of debugging.

Similarly, I've already spent hours of my live dealing with null and undefined value errors, and I'd like to stop doing that. So I welcome new languages and new language features that help to stop those errors before they happen.

[1] https://blog.overops.com/the-top-10-exceptions-types-in-prod...

Important distinction: Default is something you have to opt into for your types. It is not pervasive.