Live data from Hacker News

Having fun with Go's nil, interfaces and errors

katcipis.github.io

41–50 of 52 posts

Re: Having fun with Go's nil, interfaces and errors

#41
post #28

Earlier quoted context omitted.

They don't have the same feature of "I can call a method on a null value", at least, not that I've seen... You are calling them identical features when the fact is that they aren't. C# and Java both have generics, do they perform identical? Haskell has generics too, but I bet they'd throw a shit-fit if you tried to say "Oh, C# has generics too, so why would I bother with Haskell?"

The ability to call a method on a nil receiver doesn't have anything to do with what comparisons should do. Semantically, the question is whether == should compare the values or the vtables. In no other language I know of does it compare vtables.

Having dealt with languages that don't, I much prefer ones that do. The thing is, most languages DO basically check vtables, in that 2 values with different types will never be equal (unless there is implicit casting or some kind of equality override). For instance, 1 == "1" is valid, and true, in PHP, even though that is less then ideal. The difference, of course, is that most of those checks are done at compile time in many languages. Go will do some checks at compile time, but it's specifically unable to do some of them due to the "dynamics" of how interface variables work.

Re: Having fun with Go's nil, interfaces and errors

#42

Earlier quoted context omitted.

It's a stunningly difficult and surprisingly low-value proposition to create abstractions that don't leak. That's not the goal anyway: The goal is to leverage abstractions to build things. The implementation details frequently do matter. Even if your abstraction is airtight, it has to run on a real machine. When possible, it's preferable to design abstractions that have a clear implementation in terms of the lower le…

The behavior of Go's nil does not make the language any simpler to implement in any meaningful sense. The only thing it affects at the machine level is which cmp instructions are generated.

I won't defend the weird behavior of equality comparisons to nil, that definitely seems wrong. I was mostly just addressing the notion that a language needs a formal specification and must fully abstract the machine to be useful or at least not worthy of ridicule.

Re: Having fun with Go's nil, interfaces and errors

#43
post #10

Earlier quoted context omitted.

> Except it's not a language implementation detail, it's part of what the language is. Okay, but what was the rationale for designing the language like that?

An interface being equal to nil just because the value it contains is nil would be even more confusing. For example, imagine if you had two interface values, one holding a nil * T and one holding a nil * S. They would both be equal to nil, but not equal to each other, losing transitivity of equality. Also, sometimes nil is a perfectly valid value of something and can implement interfaces. You can call methods on nil…

Couldn't they also be equal to each other? If equality was defined only in terms of the value and not the vtable (to borrow pcwalton's terms), they would be equal. Are there any problems which would arise from this?

Re: Having fun with Go's nil, interfaces and errors

#45
post #27

> This is a very interesting situation (and not a very common one for me) because it is where Go’s simple errors as values decisions shines. Doing this kind of thing with exceptions would be pretty clumsy, [...] Just because a language supports exceptions does not mean you always have to use them. You can always use a helper function to catch any error and return it as a value.

Wouldn't that basically be replicating a return value-error approach, in a more cumbersome way though? You could argue that Go can use Exceptions in the same manner as X lang too, by using panic and recover... but most people seem to not like that. With Go and Rust, return value error handling is just simply nice. There's no question about if a function might error out, just look at the signature.

> Wouldn't that basically be replicating a return value-error approach, in a more cumbersome way though?

This would not be "replicating" anything, exceptions already are values in most languages. The only thing to do is wrap your call with a function, like "err = catch-all(expr)".

> ou could argue that Go can use Exceptions in the same manner as X lang too, by using panic and recover...

Except that it would be cumbersome ;-) because panic/recover works only in combination with defer[0].

> With Go and Rust, return value error handling is just simply nice.

Using non-exceptional control flow for errors can be useful depending on the circumstances. Using exceptions is simply nice in many other cases.

> There's no question about if a function might error out, just look at the signature.

Just look at the documentation. Code defensively.

[0] http://stackoverflow.com/q/3413389/124319

Re: Having fun with Go's nil, interfaces and errors

#46
Is this confusion just so that we can ask the type of a nil interface value at runtime?

A man orders coffee in a restaurant.

"Would you like it with or without cream?"

"Without"

A few minutes later the waiter returns.

"I'm sorry sir, we've run out of cream. Would you like it without milk instead?"

Re: Having fun with Go's nil, interfaces and errors

#47

I love the idea of a "read only" map (or any other type), but it seems it is just a side-effect landmine in this case. Yuck...almost strikes me as a bug as described in the article

A map is a pointer to the actual map implementation. When declared via

    var m map[T]T
you're basically writing

    var m *runtime.hmap
which is a nil pointer. Go has sane zero values, so it makes sense that reading from a nil map returns the zero value for whatever type its values are.

However, there's a trade-off: either Go's maps allow nil assignment (in a similar fashion to slice's `append') _or_ it retains its "reference" (forgive me for using that term) semantics.

Go's designers decided that maps should differ from slices in that regard, and I tend to agree. I think it'd be a mistake to have to always return a map _just_ in it's newly allocated.

Re: Having fun with Go's nil, interfaces and errors

#48
post #45

Earlier quoted context omitted.

Wouldn't that basically be replicating a return value-error approach, in a more cumbersome way though? You could argue that Go can use Exceptions in the same manner as X lang too, by using panic and recover... but most people seem to not like that. With Go and Rust, return value error handling is just simply nice. There's no question about if a function might error out, just look at the signature.

> Wouldn't that basically be replicating a return value-error approach, in a more cumbersome way though? This would not be "replicating" anything, exceptions already are values in most languages. The only thing to do is wrap your call with a function, like "err = catch-all(expr)". > ou could argue that Go can use Exceptions in the same manner as X lang too, by using panic and recover... Except that it would be cumber…

Just to clarify:

    err = catch-all(expr)
If your language does not provide a similar tool, you can't just use a function because "expr" is evaluated before the function is called. I had Lisp macros in mind when writing this. A poor man's approach that is still generic is to wrap the expression in a closure:

    err = catch-all(() -> expr)
Not too cumbersome, but YMMV.

Re: Having fun with Go's nil, interfaces and errors

#49
post #28

Earlier quoted context omitted.

They don't have the same feature of "I can call a method on a null value", at least, not that I've seen... You are calling them identical features when the fact is that they aren't. C# and Java both have generics, do they perform identical? Haskell has generics too, but I bet they'd throw a shit-fit if you tried to say "Oh, C# has generics too, so why would I bother with Haskell?"

The ability to call a method on a nil receiver doesn't have anything to do with what comparisons should do. Semantically, the question is whether == should compare the values or the vtables. In no other language I know of does it compare vtables.

Interface comparisons check both, the value and the dynamic type. Describing that as "comparing vtables" is misleading.

It the types don't match, the operands are not considered equal. Type and value have to match for two interface values to be equal. How does that not make sense?

For mismatched dynamic types you can't meaningfully compare the values in the general case, so of course you need to consider types.

Re: Having fun with Go's nil, interfaces and errors

#50
post #43
post #10

Earlier quoted context omitted.

An interface being equal to nil just because the value it contains is nil would be even more confusing. For example, imagine if you had two interface values, one holding a nil * T and one holding a nil * S. They would both be equal to nil, but not equal to each other, losing transitivity of equality. Also, sometimes nil is a perfectly valid value of something and can implement interfaces. You can call methods on nil…

Couldn't they also be equal to each other? If equality was defined only in terms of the value and not the vtable (to borrow pcwalton's terms), they would be equal. Are there any problems which would arise from this?

Equality is not necessarily defined for values of different types ("with different vtables", if you will). You can't just compare values of different type and expect a meaningful result.
Post reply on HN