Live data from Hacker News

Stunned by Go

how-bazaar.blogspot.co.nz

61–70 of 115 posts

Re: Stunned by Go

#61

Earlier quoted context omitted.

Documenting this does not solve the problem.

Its solves the problem that side effects that are not expected from the documentation of the behavior of the function are produced. It doesn't solve the "Go interface types specify minimum functionality that must be satisfied at compile time but do not limit the methods that can be called on an object received through the interface type at runtime" problem, but then, that's a fairly fundamental Go design decision, no…

The claim in the article, and I agree, and the Go maintainers agree, that it is a problem. It will never be fixed, but it is a problem (or, to put it another way, it causes serious maintainability and understandability problems, if this kind of behavior is common across API boundaries).

I also want to point out that I don't think typecasting itself is a bad thing in all cases. But you shouldn't type cast objects that don't belong to you.

Re: Stunned by Go

#62
post #27

for those not familiar with Go, here's the problem translated in C terms: "I passed a pointer to your function and it called free() on it. how dare you!"

No, that's not what the problem is. Translated to C++, the problem is "you passed a pointer to A∗, you dynamic_cast 'd it to a subtype B∗ without documenting that you did so".

Not really. You can't dynamic_cast across across protected or private inheritance boundaries, even if the function attempting it is a friend. As long as your public inheritance hierarchy maintains your contract (and they should) you're fine.

Re: Stunned by Go

#63
post #49

Supporting typecasting is hardly earth-shattering. Pretty much every statically typed programming language in actual use supports typecasts. That includes Scala, Java, C++, C, C#, Pascal, Algol, and even Ada. This title should be "stunned by shitty poorly documented library function" not "stunned by Go." There are a few languages out there that don't support typecasting. I think SML was one, for example. But they mad…

> There are a few languages out there that don't support typecasting. I think SML was one, for example. Haskell too, unless you explicitly opt in with Data.Typeable. It's arguably true in a certainly commonly-used subset of C++ as well: this type of typecast doesn't work in C++ unless you use dynamic_cast or another RTTI system (like COM). dynamic_cast only works on classes with a vtable. Many C++ projects don't use…

dynamic_cast downcasts in C++ only work across public inheritance. In particular a object that inheritance a Closable interface privately and a Reader interface publicly wouldn't allow a cross cast.

dynamic_cast isn't a loophole in the type system, it's there to strengthen it.

Re: Stunned by Go

#64
post #37
post #12

This behavior is explicitly defined in the godoc for io. I don’t see why the author should be "stunned" by a function doing exactly what it says it does.

That'll be because it's only been in the docs since they reported their issue.

You're both correct. It's been in the docs for io.Copy for a long time, and was only recently added to the http docs.

Re: Stunned by Go

#65
Go developer here. I posted this on the blog too.

""" This is a mistake, plain and simple. It was pointed out on the Go developer mailing list a few days before your post, and you can see my reply there.

NewRequest should take an io.ReadCloser. Unfortunately, due to backwards compatibility, a long standing semantic mistake like this is not something we can just fix, but we've at least documented it.

The tweet you quoted is wrong, and I want to explain why. If an interface value v is passed to a function f, then what does happen from time to time is that f will look for custom methods on v that are at least logically equivalent to the static interface type f is declared to expect. For example, io.Copy takes an io.Reader and an io.Writer and does the obvious thing, Reading into a buffer and then passing that buffer to Write. Of course, it would be nice to bypass the buffer when possible, and so there is a standard WriterTo interface that an io.Reader can also implement that, in contrast to Read, which copies into a buffer, says "read the data out of yourself and directly into this Writer". If io.Copy finds that method, it will use it, but the operation - reading - is the same. There is an analogous case for the Writer too. If you pass a value v to json.Marshal, Marshal will check to see if v implements json.Marshaler, meaning v knows how to marshal itself as JSON, in which case v is given that opportunity. Again, same operation you requested.

In contrast, if you have an io.Reader, while it might be okay to look for other Read-like methods, it is certainly not okay to look for Close. That's a very different operation, it's surprising, and it shouldn't be there. FWIW, I'm not aware of any other instances of this kind of semantic mixup in the standard library. But again, unfortunately, we can't change it until Go 2. All we can do for now is document it and move on. """

Re: Stunned by Go

#66
post #49

Supporting typecasting is hardly earth-shattering. Pretty much every statically typed programming language in actual use supports typecasts. That includes Scala, Java, C++, C, C#, Pascal, Algol, and even Ada. This title should be "stunned by shitty poorly documented library function" not "stunned by Go." There are a few languages out there that don't support typecasting. I think SML was one, for example. But they mad…

> There are a few languages out there that don't support typecasting. I think SML was one, for example. Haskell too, unless you explicitly opt in with Data.Typeable. It's arguably true in a certainly commonly-used subset of C++ as well: this type of typecast doesn't work in C++ unless you use dynamic_cast or another RTTI system (like COM). dynamic_cast only works on classes with a vtable. Many C++ projects don't use…

It's arguably true in a certainly commonly-used subset of C++ as well: this type of typecast doesn't work in C++ unless you use dynamic_cast or another RTTI system (like COM). dynamic_cast only works on classes with a vtable.

It's true that RTTI isn't used very much in C++, but I can't think of any non-trivial C++ project that doesn't include some traditional unsafe typecasts. And I have worked on a lot of C++ projects. And then there's the implicit type coercions, and the implicit constructors... ah, the good old days.

Re: Stunned by Go

#67
post #50
post #29

Earlier quoted context omitted.

It's much better for the core team to compromise a little than force everyone to update their code all the time. In particular, small semantic changes that can't be caught statically will just break people's code with no warning whatsoever. That's bad.

The end user gets to decide when they upgrade the toolchain so it wouldn't be "no warning" if they wrote about the change in the release notes. I'd much rather they break code relying on undocumented weird behavior, than document the weird behavior and keep it alive indefinitely.

That might be right - in this instance - and the actual cost might (or might not) be low - in this instance, but that's not worth breaking the promise Go has made to developers...that code remains compatible across minor forward versions.

Re: Stunned by Go

#68
post #65

Go developer here. I posted this on the blog too. """ This is a mistake, plain and simple. It was pointed out on the Go developer mailing list a few days before your post, and you can see my reply there. NewRequest should take an io.ReadCloser. Unfortunately, due to backwards compatibility, a long standing semantic mistake like this is not something we can just fix, but we've at least documented it. The tweet you quo…

Out of simple idle language-design-bystander curiosity, can you recall any other times where this class of bug has bitten?

Re: Stunned by Go

#69
post #63

Earlier quoted context omitted.

> There are a few languages out there that don't support typecasting. I think SML was one, for example. Haskell too, unless you explicitly opt in with Data.Typeable. It's arguably true in a certainly commonly-used subset of C++ as well: this type of typecast doesn't work in C++ unless you use dynamic_cast or another RTTI system (like COM). dynamic_cast only works on classes with a vtable. Many C++ projects don't use…

dynamic_cast downcasts in C++ only work across public inheritance. In particular a object that inheritance a Closable interface privately and a Reader interface publicly wouldn't allow a cross cast. dynamic_cast isn't a loophole in the type system, it's there to strengthen it.

I don't think I've ever seen C++ that inherited an interface privately.

That said, it's extremely common for classes to lack any virtual functions and thus be unusable with dynamic_cast.

Re: Stunned by Go

#70
post #65

Go developer here. I posted this on the blog too. """ This is a mistake, plain and simple. It was pointed out on the Go developer mailing list a few days before your post, and you can see my reply there. NewRequest should take an io.ReadCloser. Unfortunately, due to backwards compatibility, a long standing semantic mistake like this is not something we can just fix, but we've at least documented it. The tweet you quo…

[deleted]
Post reply on HN