Hello all, new here. Nim interests me a lot and I am experimenting with it currently but have hit a road block that I haven't found any documentation or forum posts about.
How would I create a base "class" method that I can access from instances of derived "classes"?
Set up my "classes"
# base class
type Tool = ref object of RootObj
...
# My base "class" method
method toolMethod(t: Tool, int param) {.base.} =
...
# derived class 1
type Hammer = ref object of Tool
...
# derived class 2
type Gun = ref object of Tool
...
Create some instances of derived "classes"
var hammer: Hammer = ()
var gun: Gun = ()
Now, I want to access the base method...
gun.toolMethod(5)
hammer.toolMethod(2)
So, what would be a good way to achieve this?
Edit: I've just noticed I can do the below but it's not ideal for me..
cast[Tool](hammer).toolMethod(2)
You can use procCall:
procCall toolMethod(gun, 5)
Bear in mind nim is not as OOP friendly as other popular languages such as Java/C#. Here you are not expected to use inheritance for everything.
By the way: https://github.com/nim-lang/Nim/issues/4329
Thanks for the responses guys.
Araq: Thanks. Sorry, I had proc in my example but I meant method. I basically want to have a common set of methods that can be shared among my child types and want to know some good ways to achieve this in nim.
Arrrrrrrrr: Thanks for the suggestion. That works although I still end up having to cast it as a tool - not really a problem, I was just hoping there was a way to avoid casting / be less verbose. I am interested in knowing how to do this in a nim, non-OOP way.
You are right, i forgot to add the type casting. The less verbose version is to define a base proc and put there any common code for toolMethod:
type
A = ref object of RootRef
i: int
B = ref object of A
c: char
proc baseTest(a: A) =
a.i = 1
method test(a: A) {.base.} =
baseTest(a)
method test(b: B) =
baseTest(b)
b.c = '1'
let b = B()
test(b)
echo b[]
You could try a concepts based approach:
import strutils
#https://github.com/onionhammer/nim-templates
import templates
type
HasName* = concept x
$x.name is string
HasSubTitle* = concept x
$x.subTitle is string
HasSummary* = concept x
x is HasName
x is HasSubTitle
Sellable* = concept x
x.price is float
Header* = concept x
x is HasName
# must have header proc implemented
header(x)
#Blog is HasName, HasSubTitle, HasSummary, Header
Blog* = object
name*: string
subTitle*: string
#Product is HasName, Sellable, Header
Product* = object
name*: string
price*: float
#Robot is HasName, Header
Robot* = object
name*: int
proc showName*(hasName: HasName): string = $hasName.name
proc showSubTitle*(hasSubTitle: HasSubTitle): string = $hasSubTitle.subTitle
proc discount*(sellable: Sellable, discountPercentage: float): string =
"$" & $(sellable.price - (sellable.price * discountPercentage))
proc summary*(hasSummary: HasSummary, titleH: string, subTitleH: string): string = tmpli html """
<$titleH>$(hasSummary.name)</$titleH>
<$subTitleH>$(hasSummary.subTitle)</$subTitleH>
"""
# Private Base method equivalent
proc header[T](ob: T): string = """<h1>$#</h1>""" % [$ob.name]
# Private Method override for Robot
proc header(robot: Robot): string = """Model: $#""" % [$robot.name]
# doHeader could be use as the public api for header outside of the module
proc doHeader*(h: Header): string = header(h)
var blog: Blog = Blog(name: "Jim", subTitle: "Jim is funny")
var product: Product = Product(name: "Wheel", price:21.95)
echo blog.showName() # Jim
echo product.showName() # Wheel
echo Robot(name: 1234).showName() # 1234
echo product.discount(0.1) # $19.755
echo blog.showSubTitle() # Jim is funny
echo blog.summary("h1", "h2") # <h1>Jim</h1><h2>Jim is funny</h2>
echo blog.doHeader() #<h1>Jim</h1>
echo product.doHeader() #<h1>Wheel</h1>
echo Robot(name: 41251).doHeader() #Model: 41251
echo "Done!"
Thank you guys!
Arrrrrrrrr: Thanks for the suggestion. I noticed I could do this before posting here but it still has the problem that I need to duplicate the non-base method for every class that I create. Perhaps some templating / macros can help to automate this..
honhon: I hadn't looked at concepts yet.. this looks very promising for what I want to do. I'll play around with it.