Hacker News new | past | comments | ask | show | jobs | submit login

Nil slices do cause problems. One when it's an aliased type that satisfies an interface (again with the nil interfaces!). Another is that it leads to inconsistencies: json.Marshal(([]string)nil) returns "null", for example, not "[]". Yet another annoyance caused by nils (including nil slice) is that reflect.Value becomes a lot more byzantine than it ought to have been, requiring careful use of IsValid(), Kind checks etc. when you want to deal with something that is either an interface or something else.

As for Option: Not sure how that's an argument. And anyway, a language with real sum types will never allow going down a branch that doesn't receive a correctly matched value.




> One when it's an aliased type that satisfies an interface (again with the nil interfaces!)

It sounds like you're again confusing nil interfaces with an interface holding a nil value (in particular, there is no way to get a nil interface from a nil slice). Here's an example that demonstrates nil slices do not cause problems: https://play.golang.org/p/tSA_otqg3-

> Another is that it leads to inconsistencies: json.Marshal(([]string)nil) returns "null", for example, not "[]".

1. This is unrelated to the language; it's the behavior implemented by the JSON library

2. This behavior is correct; a nil slice is not the same as an empty slice:

        fmt.Println([]int(nil) == nil) // true
        fmt.Println([]int{} == nil)    // false
3. This behavior is consistent: https://play.golang.org/p/NjdO0boHln

> As for Option: Not sure how that's an argument.

You posited that Go's nils are bad because you can satisfy an error interface with a pointer type, and then when you return (*ConcreteType)(nil), your error handling code executes. The problem here is unrelated to nil or to interfaces; the problem is that you're nesting one binary type inside another (binary in the literal sense of having two states, either nil or not nil in this case). You would have the same problem in Rust had you done Result<Foo, Option<ConcreteError>> or (in the case of a single return value) Option<Option<ConcreteError>>. You would fix the problem in either languages by recognizing that you only have 2 states (error or not error) and removing the nesting (in Rust: Result<Foo, Error> or Option<Error>; in Go `return ConcreteType{}`).

> And anyway, a language with real sum types will never allow going down a branch that doesn't receive a correctly matched value.

I agree, and it would be nice if Go had this, but this is also not a very significant problem--this problem is blown way out of proportion.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: