This post is part of a series where I do my best to organize my thoughts around Go: its paradigms and usability as a programming language. I write this as a Java programmer that respects the principles of Elegant Objects.
What are “Elegant Containers”?
EO style containers maximize the reuse of the highest abstractions possible, do not add unnecessary attributes or “getters”, and earn our respect because they know how to do their job.
Scenario
We need to create and fetch products. We also need to segregate products into regular and premium classes. Premium products cannot be priced below $1000.
Java Example
This design has several interesting properties:
Products can be iterated over in a for-each loop
The semantics of “Products IS-A Iterable<Product>” just works
Any Product created will be viewable in a subsequent for-each traversal
High cohesion: AllProducts focuses on all products, while Premium focuses on enforcing premium pricing rules.
Any Iterable<Product> can be decorated with another Iterable<Product>
Iteration is lazily-evaluated
Can it be done in Go?
Elephant in the room:range only works on arrays and slices (those two are the only applicable types within scope of this blog post). That’s right: unlike in Java, canonical for-each loops in Go can only be done against arrays or slices, instead of against an interface. This immediately negates several points above.
Not iterating against an interface means decorators lose the ability to lazyily evaluate the decorated object. This has implications for performance.
However way you slice it, any “iterable” decorators will have to preload the entire decorated array and operate on that.
So, barring that, how would this all look like in Go?
There are a couple of problems here;
Products is not a “smart” container - see point #3 in the Java proposal. You would have to manually append the newly-created Product to Products