I tried to run code with or without that {.base.} mark and the result is the same. Why it's needed?
type
Parent = object of RootRef
a: int
Child = object of Parent
b: int
method somefn(p: Parent): string {.base.} = "parent"
method somefn(c: Child): string = "child"
let p = Parent()
let c = Child()
echo p.somefn()
echo c.somefn()
In my example with the geometric shapes the base pragma was necessary. But that was in April, maybe it is now obsolete.
http://ssalewski.de/nimprogramming.html#_object_orientated_programming_and_inheritance
I have never used methods with Nim in real live, so I am not sure. And indeed, when I first read about about the base pragma maybe 5 years ago it confused me, I had to write my own example to see that is was necessary in same cases.
{.base.} is like virtual in C++. It marks that a method can be overloaded in subclasses and dynamically dispatched.
The pragma isn't having any effect because your example doesn't actually use dynamic dispatching, for a couple of reasons.
First, dynamic dispatching pretty much requires ref, because it requires a situation where the runtime type of the object isn't known at compile time.
Second, in your example the variable c has type Child, so c.somefn() is known at compile time to refer to Child 's method.
Try this:
type
Parent = ref object of RootObj
a: int
Child = ref object of Parent
b: int
method somefn(p: Parent): string {.base.} = "parent"
method somefn(c: Child): string = "child"
var p = Parent()
let c = Child()
echo p.somefn() # "parent"
echo c.somefn() # "child"
p = c
echo p.somefn() # "child"
I tried removing the base pragma, and surprisingly the output didn't change, but I did get a warning use {.base.} for base methods; baseless methods are deprecated [UseBase], so I suspect it added {.base.} implicitly.