5 ms·
Struct composition with Go
- shoo 11y agoSince the purpose of this is apparently to provide a fake structure to test against - would another viable approach have been to implement a trivial `Close` function that doesn't do anything? (context: i am no gopher) (edit/tangent: i wonder how method calls from inside method calls are resolved when the names are ambiguous?)
- Sphax 11y agoYou need quite a few more method to be a net.Conn actually: http://golang.org/pkg/net/#Conn http://golang.org/pkg/net/#Conn. Easier to just overwrite the Write() method like this in that case.
- Matt3o12_ 11y agoIf you just need a close that does not do anything, go has a pretty cool wrapper: `ioutil.NoopCloser`. It takes a reader and returns a reader that can be closed `io.ReadCloser`. Very useful for testing/mocking
- TheDong 11y agoI suspect your tangent is because you don't fully understand how composition works. Basically, it's weaker than you think I believe. I tried to write an example that demonstrates why I don't think the ambiguity you're referring to is possible. https://play.golang.org/p/TyMJbOjDdZ https://play.golang.org/p/TyMJbOjDdZ
- zenocon 11y agoThis is cool, but I find this snippet a tad bizarre: client, server := net.Pipe() var buf bytes.Buffer client = &recordingConn { Conn: client, Writer: io.MultiWriter(client, &buf), } While it seemingly works, it seems confusing to assign client to an internal field of a new struct, and then overwriting that same client variable with the newly created struct...not to mention passing it into MultiWriter. Anyway, I like those short posts like this. I've done similar things with embedding and struct "reconstruction" in order to elicit more testable code. It's powerful and useful, indeed.
- gohrt 11y agoWhat is the benefit of re-using the 'client' identifier? There's no closure capturing the identifier. Compare: client, server := net.Pipe() var buf bytes.Buffer client = &recordingConn { Conn: client, Writer: io.MultiWriter(client, &buf), } vs tempClient, server := net.Pipe() var buf bytes.Buffer client = &recordingConn { Conn: tempClient, Writer: io.MultiWriter(tempClient, &buf), } The latter is less confusing to me.
- deleted 11y ago[deleted]
- deleted 11y ago[deleted]
- justinsb 11y agoIs it reasonable to think of this as multiple inheritance?
- davecheney 11y agoNope, this is composition, not inheritance.
- justinsb 11y agoIt looks more like inheritance: the methods on net.Conn & io.Writer are automatically exposed. Are you saying that it is composition because you are "inheriting" from interfaces, which isn't traditional inheritance? Or if not, can you explain why you think of this as composition and not inheritance? Edit: On further thought, this looks to me like composition with automatic delegation (a huge productivity benefit of inheritance). It is unusual because the combined class also implements the interfaces because of Go's interface rules, but I think that the late-binding to implementations is more similar to composition.
- jaekwon 11y agoThe inner structs (of which the outer writer struct is composed) cannot access any of the functionality or fields outside of itself. Each inner struct is completely encapsulated, so you can't override an inner struct method and expect the inner struct's behavior to change. The accessibility of inner struct methods from the outer struct is a syntactic convenience. Java: https://gist.github.com/jaekwon/8025b9f3a482b3219a21 https://gist.github.com/jaekwon/8025b9f3a482b3219a21 Go: https://gist.github.com/jaekwon/0f6e5555ab6a592aa4c8 https://gist.github.com/jaekwon/0f6e5555ab6a592aa4c8 Once you Go, you never go back. ;)
- pcwalton 11y agoThere are also no virtual methods with struct composition. If B embeds A, "upcasting" an instance of B to A will not allow you to call any methods on B.
- 11y ago
- nevergo 11y agoYeah, dumb go kids enjoy the Nothing...
- aleksi 11y agoIn the end there is no need to embed (exported) io.Writed, it should be replaced with non-exported non-anonymous field.