Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

You don't have to keep explaining the mechanism. I get the mechanism. But the fact that `foo == nil` can return false when foo is actually nil is indefensible. The fact that it crashes less than C does is not a defense here. Sorry.


But foo isn't nil.

I'll agree with the opinion that it can be confusing that an interface consists of two elements, the type and the value itself, and that the "== nil" check may not do what you initially expect, because the interface values are hidden below the surface of the abstraction the language provides. But it is not true to say that "the interface value is nil", because it factually isn't. To use psuedo-Go, since neither "Interface" nor the types are first-class values, Interface{ConcretePointerType, nil} does not and should not compare as equal to nil. There are values in memory corresponding to this interface value, and those values do not correspond to any interpretation of "nil" Go uses. We're talking about real numbers in real RAM here and a real specification of nil that corresponds to those real numbers in RAM; this is not a matter of opinion.

I don't know of any language that doesn't have a few dozen quirks of this sort buried in it. It can be pointed out as a legitimate criticism of the language, but it's not particularly a flaw relative to other languages. Either it's not possible to build a truly clean programming language that lacks this sort of quirk, or we're not very good at it.

Before replying to me with the language you believe lacks these quirks, please do me a favor and search for "$LANGUAGE quirk" and "$LANGUAGE gotcha" first, because that's the first thing I'm going to do. And it won't be a defense to me to explain how what you found is not really a quirk because you just have to properly understand the language, because that defense is true for this quirk of Go's too.


i think people get so tripped up by this because they expect equational reasoning to work:

   a = nil
   b = a
   // => b == nil, right? but no.
one of the devs on /r/golang posted he wished they had used a different keyword like "unset" to check for an empty interface, which would be much less intuitively confusing.

i agree all languages end up with quirks like this (can't get everything right without really using the language, and by then it's too late!), and in fact go is low on the quirk level in my opinion.

the other one i really wish i could change is that

    for i, x := range foo
doesn't give x a new binding each time through the loop. Confusing, and almost never the behavior you want.


    But the fact that `foo == nil` can return false when foo is actually nil is indefensible. 
You keep saying this, but it's not true.


Only because go has redefined the terms.

    …

    foo = nil
    bar = foo

    // this check may or may not evaluate as true
    if (bar == nil) {
       …
    }
Saying that `bar` here isn't actually equal to nil if it's an interface is tautological. It's not, but only because the language has defined this to be the case. Go could likewise define `1 == 2` to evaluate to true, and you could reuse the same semantic reasoning to defend it.

The point being argued is that it doesn't matter that go defines this to be the case, the point being argued is that it's surprising, frustrating, and can lead to bugs. Particularly when `bar` starts off as a pointer to a struct, but later is refactored to be an interface type. Code that used to work still compiles, but now encounters a runtime nil panic.


(See also my response to jerf, above.)

In Go (as in most programming languages) it's not true that the assignment "a = b" implies that "b == foo => a == foo", if a and b are different types.

For example, this C code will print "nope":

    float b = 3.5;
    int a = b;
    printf(a==3.5 ? "yup" : "nope\n");
So back to Go, sure, this is initially surprising, and most people get bit by it at first. Once you know about it, it's fine.

In practice I haven't encountered any refactoring bugs as you describe, though it is theoretically possible.

I personally don't see it as a big issue.

(In retrospect, Go could've help guide intuition better by using a new keyword like "unset" or something to test for the zero-value of interfaces, instead of overloading nil.)


> In Go (as in most programming languages) it's not true that the assignment "a = b" implies that "b == foo => a == foo", if a and b are different types.

While I haven't counted and compared, I suspect that in most programming languages, "a=b" being a non-error implies that either a and b are the same type and value, or that a and b are values that, if they are of different and comparable types, will compare equal.

There are certainly popular languages that do it the way you describe, but I don't think most languages do.


That's a fair point.


> In Go (as in most programming languages) it's not true that the assignment "a = b" implies that "b == foo => a == foo", if a and b are different types.

While this is true, in all of those other cases you have the benefit of compile-time type checking so cannot call a function on the wrong type.

With nil, you get runtime errors.




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

Search: