After many many hours of trying to make this work, I finally got it to go. I 
suspect I'm not the only person to struggle with this, so I figured I'd 
document the answer here.

Rather than getting into theoreticals, let's just jump into code.

Nim supports inheritance for objects. An example:
    
    
    # Parent object
    
    type
      Animal = ref object of RootObj
        id: int
    
    method sayFeet(a: Animal): string =
      result = "[" & $a.id & "] has an unknown number of feet"
    
    # Child object
    
    type
      Dog = ref object of Animal
        hairLength: float
        legCount: int
    
    method sayFeet(d: Dog): string =
      result = "Dog [" & $d.id & "] has " & $d.legCount & " feet."
    
    # Child object
    
    type
      Cat = ref object of Animal
        whiskerCount: int
        pawCount: int
    
    method sayFeet(c: Cat): string =
      result = "Cat [" & $c.id & "] has " & $c.pawCount & " feet."
    
    # generic proc
    
    proc describe(foo: Animal) =
      echo "animal detail: " & sayFeet(foo)
    
    # use it
    
    var
      sparky = Dog(id: 1, legCount: 4)
      mittens = Cat(id: 2, pawCount: 4)
    
    sparky.describe()   # "animal detail: Dog [1] has 4 feet."
    mittens.describe()  # "animal detail: Cat [2] has 4 feet."
    
    
    Run

Yes, this and all the examples are silly. This more about proof-of-concept.

Nim also supports generics in object types. Among other things, this allows for 
compile-time optimization.
    
    
    type
      Domestication = enum
        Wild
        Feral
        Domestic
    type
      Animal[wildness: static[Domestication]] = ref object of RootObj
        id: int
    
    proc sayFeet(a: Animal): string =
      result = "[" & $a.id & "] has an unknown number of feet"
    
    proc describe(foo: Animal) =
      when foo.wildness == Wild:
        echo "Wild animal detail: " & sayFeet(foo)
      elif foo.wildness == Feral:
        echo "Feral animal detail: " & sayFeet(foo)
      else:
        echo "Tame animal detail: " & sayFeet(foo)
    
    var
      sparky = Animal[Feral](id: 1)
      mittens = Animal[Domestic](id: 2)
    
    sparky.describe()   # "Feral animal detail: [1] has an unknown number of 
feet."
    mittens.describe()  # "Tame animal detail: [2] has an unknonw number of 
feet."
    
    
    Run

But, can you put both ideas together? Yes, but there are apparently a few 
things to keep in mind.

The example of both:
    
    
    # Parent object
    
    type
      Domestication = enum
        Wild
        Feral
        Domestic
    
    type
      Animal[wildness: static[Domestication]] = ref object of RootObj
        id: int
    
    proc sayFeet(a: Animal): string =
      result = "[" & $a.id & "] has an unknown number of feet"
    
    # Child object
    
    type
      Dog[wildness: static[Domestication]] = ref object of Animal[wildness]
        hairLength: float
        legCount: int
    
    proc sayFeet(d: Dog): string =
      result = "Dog [" & $d.id & "] has " & $d.legCount & " feet."
    
    # Child object
    
    type
      Cat[wildness: static[Domestication]] = ref object of Animal[wildness]
        whiskerCount: int
        pawCount: int
    
    proc sayFeet(c: Cat): string =
      result = "Cat [" & $c.id & "] has " & $c.pawCount & " feet."
    
    # generic proc
    
    proc describe(foo: Animal) =
      when foo.wildness == Wild:
        echo "Wild animal detail: " & sayFeet(foo)
      elif foo.wildness == Feral:
        echo "Feral animal detail: " & sayFeet(foo)
      else:
        echo "Tame animal detail: " & sayFeet(foo)
    
    # use it
    
    var
      sparky = Dog[Feral](id: 1, legCount: 4)
      mittens = Cat[Domestic](id: 2, pawCount: 4)
    
    sparky.describe()   # "Feral animal detail: Dog [1] has 4 feet."
    mittens.describe()  # "Tame animal detail: Cat [2] has 4 feet."
    
    
    Run

Some things to watch out for:

  * For inheritance in general, you really need "ref object" rather than 
"object" objects. Things get lost otherwise.
  * Notice the ref object of Animal[wildness] on the child object definitions. 
The parent object reference must include the generics.
  * Inheritance WITHOUT generics: use "method" not "proc". WITH generics, use 
"proc" not "method". And no, I don't know why.



Hopefully this is helpful to somebody. :-)

Reply via email to