4 ms·
This is a bad practice in Go for any interface type. Interfaces which are wrapped will fail all type assertions against their original type and fail to assert i
by inlined 7y ago
This is a bad practice in Go for any interface type. Interfaces which are wrapped will fail all type assertions against their original type and fail to assert into additional interfaces that the original also implemented.
For example, imagine you have an io.Reader. It may actually implement io.ReaderTo which is used in some cases to implement alloc-free copying. If you wrap it into a new struct, e.g. ioutil.NopCloser you delegate the main interface but not the bonus interfaces. You can no longer cast to the type of the original reader interface either (concrete type comparison is more important with errors, which had a custom fix in Go just for this)
- fabianlindfors 7y agoIf we have an io.Reader which implements io.ReaderTo then it has a certain set of exported functions. If this is embedded in ioutil.NopCloser then all those exported functions will be available on ioutil.NopCloser. Wouldn't structural typing then ensure that ioutil.NopCloser implements io.ReaderTo as well as io.Reader? Sorry if I'm misunderstanding!
- tedunangst 7y agoNopCloser returns an io.ReadCloser. Where are the extra functions?
- omegabravo 7y agohttps://play.golang.org/p/V3eWfbDGhXF https://play.golang.org/p/V3eWfbDGhXF In this example, by wrapping an interface in another interface, you lose the ability to cast back down to an interface that the original type fulfilled.
- fabianlindfors 7y agoThanks for putting that together, I see your point know. Thought you were talking about embedding when you said "wrap" before. Considering that this is not related to embedding specifically, would you say that decorators in general are bad practice in Go?
- weberc2 7y agoThis is often a reasonable thing to do (encapsulation). Callers don't have a right to private details, and I would go further and say that an interface value's concrete type is itself an implementation detail that callers shouldn't depend on unless the interface's documentation declares it stable.
- weberc2 7y agoThis might be a bad practice, but I don't feel very bad if you subvert the type system like this and it bites you. If `io.ReaderTo` is important, it should be a bonafide first-class method, not something that's determined and dispatched to via reflection.
- inlined 7y agoThis is the way that “optional” methods work in Go. For example, go decided not to rebuild the entire HTTP library to support web sockets. Instead, supported servers will pass an http.Request that also implements http.Hijacker for letting a request stay alive after the Handler closure
- weberc2 7y agoI get it, but I disagree with subverting the type system. The type system is there to promote safety and maintainability; you shouldn't subvert it even if "you" are the std lib.