In this example, ThingWithMetadata does the caching. image.fetch_metadata fetches the image and returns it. It’s up to the caller (in ThingWithMetadata) to cache the returned value.
But part of the goal is to not need the caller to cache it. Nor have the class that knows how to fetch it need to know how to cache it either. The responsibility of knowing how to cache the value is (desired to be) in the MetadataSource interface.
The rule is that you can't cache a value in an interface, because interfaces don't store data. You need to cache a value in a struct somewhere. This implementation wraps items (like images) in another struct which stores the image, and also caches the metadata. Thats the point of ThingWithMetadata. Maybe it should instead be called WithCachedMetadata. Eg, WithCachedMetadata<Image>.
You can pass WithCachedMetadata around, and consumers don't need to understand any of the implementation details. They just ask for the metadata and it'll fetch it lazily. But it is definitely more awkward than inheritance, because the image struct is wrapped.
As I said, there's other ways to approach it - but I suspect in this case, using inheritance as a stand-in for a class extension / mixin is probably going to always be your most favorite option. A better approach might be for each item to simply know the URL to their metadata. And then get your net code to handle caching on behalf of the whole program.
It sounds like you really want to use mixins for this - and you're proposing inheritance as a way to do it. The part of me which knows ruby, obj-c and swift agrees with you. I like this weird hacky use of inheritance to actually do class mixins / extensions.
The javascript / typescript programmer in me would do it using closures instead:
> The rule is that you can't cache a value in an interface, because interfaces don't store data.
Right, but the start of where I jumped into this thread was about the fact that there are places where fields would make things better (specifically in relation to traits, but interfaces, too). And then proceeding to discuss a specific use case for that.
> A better approach might be for each item to simply know the URL to their metadata.
Not everything is a coming from a url and, even when it is, it's not always a GET/REST fetch.
> but I suspect in this case, using inheritance as a stand-in for a class extension / mixin is probably going to always be your most favorite option
Honestly, I'd like to see Java implement something like a mixin that allows adding functionality to a class, so the class can say "I am a type of HasAuthor" and everything else just happens automatically.