> they make use of interfaces/protocols/traits
Oh I very much agree, I love interface polymorphism.
> "No Bottle", "One Bottle", [etc] are distinct things and should be represented accordingly
I completely disagree. The problem is to generate a 100-line poem, line by line. Our challenge is to express the rules which govern how to derive a line from its line number in the clearest way possible. Creating an ontology for bottle types makes that overcomplicated. What if there were a special rule for bottle numbers divisible by 3? What if there were a special rule for doubled digits? Would we need to create a DivisibleByThreeWithDoubleDigitsBottle using multiple inheritance to write a line for 66 bottles? Why?
The big gift of OOP is interface polymorphism. The big curse of OOP is the philosophy that objects should model "real distinct things." Object-oriented domain modelling often causes more problems than it solves. Clear dataflow, cohesively represented logic, and loosely coupled modules are much more important than some philosophical notion about what sorts of ideas ought to be given associated objects. That's how you get Joe Armstrong's "gorilla holding the banana and the entire jungle."