2 ms·
I agree that this is a problem, but the problem is not that interfaces have multiple kinds of nility. The issue here is that you’re putting a pointer type into
by throwaway894345 5y ago
I agree that this is a problem, but the problem is not that interfaces have multiple kinds of nility. The issue here is that you’re putting a pointer type into an interface and it’s easy to forget that the runtime type is effectively a reference to a reference, both of which can be nil.
Any preferred solution (which will never happen due to compatibility guarantees) would be to eliminate zero types altogether and use Rust-like enums instead.
- TheDong 5y agoThe problem I'm highlighting is not that I, the programmer, am forgetting it, but that it can change depending on context without the specific line changing. Go's type inference can take: x, err := 1, someNilStruct And have that mean either "err is now a nil struct type" or "err is now a non-nil interface". Which of those things it does depends on the types of existing variables in scope or function signatures. On the other hand, in rust if I type "let err = rhs", that will _always_ introduce a new variable named err that is the same type no matter what lines of code are above me. The interaction there in go is due to poor interactions between features other than zero types I think, so I don't see dropping all zero types as solving it. I also don't think zero types are analogous to rust enums, but rather to rust's default trait (which I do vastly prefer over zero types).
- throwaway894345 5y ago> Go's type inference can take: `x, err := 1, someNilStruct` And have that mean either "err is now a nil struct type" or "err is now a non-nil interface". Which of those things it does depends on the types of existing variables in scope or function signatures. You’re mistaken here. `err` will always have exactly the same type as `someNilStruct`. Specifically you’re confusing the variable declaration syntax with the variable assignment syntax. `err := foo` is the same as Rust’s `let mut err = foo` in that `err` will have exactly the same type as `foo` no matter the types of other variables. `err = foo` behaves exactly the same in Go as in Rust in that you’re just reassigning the value of `err` but it’s type doesn’t change.
- anonymoushn 5y agoThe spec says > Unlike regular variable declarations, a short variable declaration may redeclare variables provided they were originally declared earlier in the same block (or the parameter lists if the block is the function body) with the same type, and at least one of the non-blank variables is new. This suggests that a redeclaration as part of a short assignment will not change the type of the previously-defined err. is the spec incorrect? Edit: Here's a demonstration of this sort of thing https://go.dev/play/p/Po_Uy85ORN_L https://go.dev/play/p/Po_Uy85ORN_L. You can uncomment line 22 to change the meaning of the assignment on line 23 and cause the program to segfault.
- TheDong 5y agoThe playground link I have two comments ago shows exactly the behavior I describe, that multiple assignment exhibits exactly the behavior I describe. Click through to the playground link and add some 'fmt.Printf("%T\n", err)' lines here and there to see what I mean.
- Joker_vD 5y agoOkay, I've accidentally put a pointer type into an interface, now what? How do I check that the inner value is nil/not nil? Mmmmm? It's a defect in the language, plain and simple: if a pointer-to-type implements interface, then converting a nil pointer to type to the interface should result in a nil interface value (that would compare equal to nil) instead of a non-nil interface value that has nil value pointer inside it — which is a second kind of nil in anything but name. You compare it to nil, it says "not nil", then you try to use it and it blows up with panic "I am actually a nil, gotcha sucker".
- throwaway894345 5y ago> Okay, I've accidentally put a pointer type into an interface, now what? How do I check that the inner value is nil/not nil? Mmmmm? What does this even mean? If you did it by accident it sounds like a bug in your program, so fix the bug so a nil can’t be passed into the interface. If it’s not a bug but nil is a valid value, then type-assert the interface back to the concrete pointer type and check it against nil. > It's a defect in the language, plain and simple: if a pointer-to-type implements interface, then converting a nil pointer to type to the interface should result in a nil interface value (that would compare equal to nil) instead of a non-nil interface value that has nil value pointer inside it — which is a second kind of nil in anything but name. No, this would be a bug because a nil pointer and a nil interface mean different things. > You compare it to nil, it says "not nil", then you try to use it and it blows up with panic "I am actually a nil, gotcha sucker". You have the same behavior in any language with nullable references including Java, Python, C, etc. You’re complaining ultimately because you don’t understand references. In this case you have a reference type (the interface) whose value is itself a reference type and you’re upset because checking the outer reference for nil doesn’t also evaluate the inner reference; however, no mainstream language works this way and this would be very surprising behavior to people who actually understand references.
- anonymoushn 5y agoGP may have in mind that most other languages would let you write *ptr == NULL if someone handed you a pointer to a null pointer to a specific implementation of an interface even if you didn't know which specific implementation.