The impact on middleware of expanding APIs with Go's interface smuggling
utcc.utoronto.ca
utcc.utoronto.ca
Rclone has backends which connect to cloud providers. These all implement a common interface. So far so good.
However some cloud providers can implement optional features, say a server side copy of an object.
Rclone used to use interface upgrades to discover these. Still so far so good.
However rclone has backends which wrap other backends, for example the crypt backend which encrypts file names and data.
This backend has to implement all the optional features - you want to be able to server side copy an encrypted file if possible.
The problem comes when the crypt backend wraps another backend which does not support server side copy.
What rclone used to do here is return a special not implemented error. This works, but isn't ideal because you have to call the method to find out if it is supported and often you'd like to know before that.
I eventually gave up on interface upgrades and resorted to good old function pointers which you can check against nil. When the crypt backend starts up it finds out whether the backend it is wrapping supports server side copies and if not nils the pointer.
A little bit of reflection removed the boiler plate for this and it turned out quite neatly.
If instead there was a way for crypt to remove methods from its method set then that would be a better solution.
The first attempt to fix it was to use dynamically generated proxies. The IAdaptable mechanism proposed by Ken Beck is an example of that for Eclipse [1].
This was ultimately fixed by introducing default methods which is as restricted way of implementing Traits [2] in Java 8.
I guess Go will have to follow a similar direction.
[1] https://wiki.eclipse.org/FAQ_How_do_I_use_IAdaptable_and_IAd...
[2] https://en.wikipedia.org/wiki/Trait_(computer_programming)
I swear go is different and doesn't need to learn from mistakes from other languages, because after all, you don't need that with go…
Instead of being arrogant maybe go designers should have listened to the people who told them 10 years ago that these issues were real, and not a product of "bad coding practices". Because this:
> . The Prometheus people try hard to do it anyway, and the result is rather messy and involves a combinatorial explosion of the possible combinations of APIs.
Is madness.
Go didn’t get everything right, but I’m happy it’s not Java.
Go has benefitted immensely from not starting out looking like Java from day 1
But it actually kind of did when it comes to generics.
> Go didn’t get everything right, but I’m happy it’s not Java.
Well a good thing generics are on their way then?
I’m not sure if generics will be a net benefit to Go. I often wish I had them, but I rarely need them to make code type safe. Further, I don’t think Go will be able to retain its property that solutions implemented in ago tend to be flat-footed/boring/not-overly-abstract nor the property that different developers tend to approach similar problems in very similar ways (I.e., Go tends to be written in very standard ways). Of course, if you’ve never used Go for a considerable time, you will likely devalue these properties, but they turn out to be really useful, especially in a collaborative setting. Maybe they won’t be lost when generics arrive, or maybe generics will be a net positive. I hope so, but I’m concerned. I think Go is quite a lot nicer to read and write than other languages with generics, and I would be sad if it backslid.
The key here, is the object can implement this any way it wants.
A typical "static" object would just return itself as the requested interface for the interfaces it supported. But a proxy object, with a wrapped upstream object, could pass through requests for interfaces it didn't know or need to override to the upstream object.
I don't know Go, but a quick google makes me think type assertion is the mechanism for getting an interface from an object at runtime. So if Go allowed a type to override type assertion, I think that should enable middleware and other proxy objects to behave well.
It is indeed possible to add build constraints to .go files to have them included for compilation only on specified minimum versions of Go, see [1]
I know, every language suffers from this to some degree, but somehow it feels like go gets bitten a lot more than the others (except maybe PHP).