I come from a different school of languages so I would perhaps do something
like the following:
warehouse.nim:
type
# We want everything on the shelf to be a Box
Box* = ref object of RootObj
Warehouse* = ref object
shelf: seq[Box] # We do not use * to export the shelf
# IMHO these procs should be in this module, not the other way around,
# encapsulation is better.
proc pushbox*[T: Box](w: Warehouse, b: T) =
w.shelf.add(b)
# Fiddling with [T] here didn't fly which I suspect has to do with
# the simple fact that we don't know what is coming out from the
# seq until at runtime.
proc popbox*(w: Warehouse): Box =
w.shelf.pop
# Nim style constructor proc
proc newWarehouse*(): Warehouse =
Warehouse(shelf: newSeq[Box]())
box.nim:
import warehouse
type
BoxOfEggs = ref object of Box
number: int
BoxOfBananas = ref object of Box
color: string
Banana = ref object of RootObj
var eggs = BoxOfEggs()
var bananas = BoxOfBananas()
var banana = Banana()
var warehouse = newWarehouse()
warehouse.pushbox(eggs)
warehouse.pushbox(bananas)
# Below line will not compile:
# Error: type mismatch: got (Warehouse, Banana)
# but expected one of:
# proc pushbox[T: Box](w: Warehouse; b: T)
#
#warehouse.pushbox(banana)
# Here we get a Box out of popbox, but the runtime Conversion is type safe
# so will cause a runtime ObjectConversionError if it's an BoxOfEggs or
vice versa
var myBananas: BoxOfBananas
myBananas = BoxOfBananas(warehouse.popbox())
var myEggs: BoxOfEggs
myEggs = warehouse.popbox().BoxOfEggs # Different syntax style
# Below line will not compile:
# type mismatch: got (Box) but expected 'Banana = ref Banana:ObjectType'
#var myBanana: Banana = Banana(warehouse.popbox())