4 ms·
I find the comparison to java a bit unfair, because this pattern is totally possible but has been largely deemed a bad pattern. The analog to the pattern in jav
by avita1 7y ago
I find the comparison to java a bit unfair, because this pattern is totally possible but has been largely deemed a bad pattern. The analog to the pattern in java is to extend from a non-final class. So in this case "class HTTPClient" and "class CachedHTTPClient".
There are lots of drawbacks to doing it that way, the worst of which is that you need to remember to override the method in CachedHTTPClient everytime you add a method to HTTPClient, and the compiler gives you no hints about it.
- deleted 7y ago[deleted]
- fabianlindfors 7y agoMy Java experience is admittedly limited so thanks for pointing that out! What happens in case you forget to override the method in CachedHTTPClient?
- fredrik-j 7y agoIf an extending class does not implement a method which is implemented by its super class, a call to that method on a instance of the extending class will invoke the super class' implementation of the method. The super class implementation of the method may perform something that is entirely correct even for the extended class, or it may do something that is inconsistent with the assumptions of the extended class. Either way, there is no way for the compiler or runtime to determine if the omission of the method in the extending class is intentional or a mistake. This is one reason to prefer Composition over Inheritance, especially in Java.
- skybrian 7y agoYes, that usually would work, but it's more error-prone than composition, because there may be calls in the base class to the method you overrode. You could even inadvertently create infinite recursion.
- jerf 7y agoIt's important to deeply understand why patterns are deemed bad in one language, so you can see if it applies to another language [1]. In the case of Go, we generally try to keep interfaces small. In many real-world cases of decoration in Go, probably the vast, vast majority, the interface only has one method, so there isn't any way to forget to override the other methods. While there's no particular exact language feature I can point at to say why this happens, in general, Go interfaces are more fluid since they don't have to be declared up front, and end up being kept simpler than Java classes and interfaces, so the concerns about failing to override other methods are greatly, greatly reduced. They are not technically eliminated, but they're pushed way, way down my list of priorities. [1]: This is not special pleading for Go, it goes well beyond that. A good design in Java is a bad design in Python, a good design in Python is a bad design in Java, etc. If you had two languages where the exact same patterns were appropriate in the exact same way, I'd question whether you actually had two languages.
- jayd16 7y agoThis doesn't protect you in the slightest. The failure case is clear and likely for something like an CachedHttpClient where every call should be cached. You're talking hypothetically but here's a simple common failure case.
- jerf 7y agoHow do you fail to implement the second method override on a single-method interface? Bear in mind that when using the interface, the interface is all there is. It essentially erases the other methods from consideration. That's why an interface value in Go is a distinct type; it isn't just "a thing that can happen to hold all these various concrete values", it is a distinct thing with its own method set. So discussion underlying structs and their method sets is a category error. (This is a bit subtle, but important to understand what is actually going on in Go, or any other language with a similar setup.) I'm not talking hypothetically. I'm talking about what happens in real Go code. Discussing what could happen if people wrote interfaces in a way other than they actually do is what is hypothetical. This is the sort of thing that matters when deciding whether or not a particular pattern is useful in a language. It's rarely entirely down to pure syntax concerns or some sort of Platonic software engineering consideration. In fact, even within the same language you can encounter situations where a pattern makes sense in one framework but is a bad idea in another framework; Javascript is full of such things. (Whether that's for good or bad reasons is a separate consideration; the fact is that it is full of them.)
- jayd16 7y agoYes I think the snarky 'bad way Java does this' (ie implement the base interface entirely and call into HTTPClient from the outside) is actually a lot safer.