Live data from Hacker News

Stunned by Go

how-bazaar.blogspot.co.nz

101–110 of 115 posts

Re: Stunned by Go

#101

Earlier quoted context omitted.

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…

> The claim in the article, and I agree, and the Go maintainers agree, that it is a problem.

I don't think that's accurate. What the Go maintainers seem to agree is that this particular use of the capability to use run-time interface querying on the received value to exceed the capabilities of the interface through which the object is received is problematic because it isn't using an interface of similar semantic role, and this is the kind of thing that would likely be fixed now but for the commitment not to make breaking changes in Go 1.x.

They do not appear to agree that "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" is a problem, just a feature that, while provide a valuable benefit, can also be used in less-than-ideal ways (of which this is an example.)

> But you shouldn't type cast objects that don't belong to you.

On this point in particular, I see no evidence that the Go maintainers agree.

Re: Stunned by Go

#102
post #99

Earlier quoted context omitted.

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

No. A related bug would be if you implement Read and (say) ReadByte, but your ReadByte is buggy. Then when you get weird behavior passing yourself to something that expects a Reader (but internally needs byte-at-a-time and uses ReadByte to avoid double-buffering the input) it can take a minute or two to realize that ReadByte might be the problem and not Read. I've only seen that once or twice.

[deleted]

Re: Stunned by Go

#103
post #86

Earlier quoted context omitted.

You adopted "looking for custom methods" without making it part of the contract in any way as a best practice in the standard library, but it is a "mistake, plain and simple"? Doesn't it, like, illustrate a serious language and/or standard library design issue? What can possibly motivate breaking encapsulation in the standard library? Why even have interfaces if even the standard library will abuse them? Your respons…

It’s not like that. It makes sense in Go. Say you have a type, and you implement “Read” function for it. You don’t do anything else but now you are implementing an interface and other functions can call your “Read” function. Having a “ReadByte” function and other functions calling that isn’t that much different from your perspective. Any type that implements “Reader” may implement similar functions too. And if they d…

Unless your ReadByte function does something different than what the function you call assumes it does.

For example, it might have different behaviour in edge cases (end of file, I/O exception). One could call that bad architecture, but one could not even be aware of the existence of the broader interface that has a ReadByte member function, or one could (IMO rightfully) think the difference does not matter of you call a method taking an argument of interface type that does not include ReadByte.

In the absolutely worst case, it does something completely unrelated to what Read does. Unlikely? Yes, but it might be part of a badly factored class that also has code for reading from an A/D converter.

Re: Stunned by Go

#104
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…

I know of atleast one instance in C# where something like this happens. The IEnumberable .Count() extension sees if the input is actually a ICollection and uses the count on that to get the count directly, rather than iterating over it. I remember writing extension methods in C# for IEnumerable , which would of course take in an IEnumerable , but saw if the actual input was a ICollection , IList etc to optimize the o…

The semantics of ICollection.Count and IList.Count are well defined and known to you at the time your write your extension method.

You don't know the semantics of a method of an arbitrary type you've been passed in just because it has the same name. Go plays fast and loose with this idea, but at least the interface type of the argument should document "I'm expecting these methods to have a particular semantics". If they don't, that's then your fault.

Re: Stunned by Go

#105

Earlier quoted context omitted.

I know of atleast one instance in C# where something like this happens. The IEnumberable .Count() extension sees if the input is actually a ICollection and uses the count on that to get the count directly, rather than iterating over it. I remember writing extension methods in C# for IEnumerable , which would of course take in an IEnumerable , but saw if the actual input was a ICollection , IList etc to optimize the o…

The semantics of ICollection .Count and IList .Count are well defined and known to you at the time your write your extension method. You don't know the semantics of a method of an arbitrary type you've been passed in just because it has the same name. Go plays fast and loose with this idea, but at least the interface type of the argument should document "I'm expecting these methods to have a particular semantics". If…

The Go dev has acknowledged that this is a bug, but also pointed out why something like this was done elsewhere ( io.Copy ), and the Count example was pointed at that.

Re: Stunned by Go

#106
Even if there is agreement that this is a problem, it strikes me that it can become a problem.

The standard library should be exemplary, what do you think would happen in the hands of a developer who's "not as smart as he thinks he is?"

Wasn't that part of go's pitch? I never really considered that libraries would go so far as to inspect the types for methods rather than just make those methods a requirement. The fact that they are able means someone else is going to use it, and it's going to bite me. Don't like.

Re: Stunned by Go

#107

Even if there is agreement that this is a problem, it strikes me that it can become a problem. The standard library should be exemplary, what do you think would happen in the hands of a developer who's "not as smart as he thinks he is?" Wasn't that part of go's pitch? I never really considered that libraries would go so far as to inspect the types for methods rather than just make those methods a requirement. The fac…

What was part of Go's pitch, exactly? And where did you see it pitched?

People outside the Go team have tried to pitch Go as a lot of things, most of them having no relationship to what Go was actually intended to accomplish.

The FAQ[1] may be enlightening. Nowhere does it say Go is supposed to be a straightjacket that makes bad programmers into good ones.

[1] http://golang.org/doc/faq#What_is_the_purpose_of_the_project

Re: Stunned by Go

#108
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…

> 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.

Interesting. This kinda sounds good in practice, assuming programmers respect the interface's semantics when downcasting. But from a language design point of view it strikes me as a bit hacky al least, and at odds with the "Tell, Don't Ask" principle.

Couldn't this need for downcasting be avoided by allowing something like default method implementations in interfaces? I'm asking this without any practical knowledge of the Go language; i'm sure different approaches have been considered, but i'm interested in understanding the reasons behind the preference for downcasting :)

Imagine the Reader interface declared, besides the Read method, a WriteTo method with a default implementation:

  type Reader interface {
      Read(p []byte) (n int, err error)
      WriteTo(w Writer) (n int64, err error) {
          // Default implementation in terms of Read and w.Write 
          // using a buffer just like io.Copy
      }
  }
Then any type with a Read([]byte) (int, err) could still be referenced as a Reader, and when seen as a Reader one could call the convenient WriteTo method without downcasting. io.Copy could then tell the objects what to do instead of asking them what they are:

  func Copy(dst Writer, src Reader) (written int64, err error) {
      return src.WriteTo(dst)
  }
A type that complies with the Reader interface could also implement a specific version of WriteTo if needed for performance reasons.

This way not only programmers could avoid resorting to downcasting, but the interfaces would become more explicit: instead Reader being "something with a Read method... and maybe a WriteTo if you want to, but this is not declared in Reader itself" it'd be "something with a Read method and a default WriteTo mehod".

The downsides of this would be that the dispatch semantics become a bit more complex for having to consider the default implementations, and maybe the interfaces could become more "bloated" (though i think that's subjective, as the semantics of an interface like Reader are implicitly mixed up with things like WriterTo; having all the methods in Reader would make that existing coupling more explicit).

Re: Stunned by Go

#110
post #7
post #3

Anyone proficient in GO would care to provide the minimal code that illustrate that extremely weird behavior ? I find that post so disturbing that i still believe i've missed something.

An example: http://golang.org/src/pkg/io/io.go?s=11741:11801#L336 Line 336. io.Copy takes a writer and a reader, but actually asserts whether they implement ReaderFrom/WriterTo, then use their methods, ReadFrom and WriteTo, if they do. (Same thing with the http package checking if the reader implements Closer, and calling Close if it does, though admittedly 'we should be able to call Close' is a much more unsafe assu…

Does Go not provide method overloading? Couldn't they have 3 versions of the copy method?
Post reply on HN