I've been trying to figure out how to track a heterogeneous group of types while using composition. What is the recommended nimic way? Do I need some basic level of inheritance to accomplish this? See wikipedia/composite_pattern In OOP I would just use a seq[BaseClass] which is straightforward in nim.
Below is my attempt at this without using inheritance. I don't know what this method of programming is called without inspecting the generated C code, but I suspect that it's actually inheritance under the hood. It also looks like it'll become rife with massive switch statements for all shared procs.
type CarMake {.pure.} = enum Tesla,Mercury
type Car = ref object
age:int
case typ:CarMake:
of CarMake.Mercury:
leather:bool
of CarMake.Tesla:
summons_mode:bool
proc newMercury(has_leather:bool):Car =
result = Car(typ:CarMake.Mercury, leather:has_leather)
proc newTesla(default_summons_mode:bool):Car =
result = Car(typ:CarMake.Tesla, summons_mode:defaultSummonsMode)
proc decay(car:Car) = inc car.age
proc summon(car:Car) =
stdout.write "Summoning your car... "
case car.typ:
of CarMake.Tesla:
car.summons_mode = true
echo "it might arrive."
of CarMake.Mercury:
echo "(calling home) They said 'No, get it yourself.' :("
var cars = newSeq[Car]()
cars.add( newMercury(hasLeather=true) )
cars.add( newTesla(defaultSummonsMode=false) )
for each_car in cars:
each_car.summon
Just use either inheritance or object variants, whichever lends itself better to your use case. You can't get sum types from composition alone, which leads to product types, and you need sum types here.
The rule "composition over inheritance" is for a different situation, where inheritance gets abused as a form of composition (for example, because a language does not support value types natively and you want to avoid additional levels of indirection). And the for the "composite pattern", composition is only part of the pattern.