You can do pretty traditional OOP in Nim if you want to (except for proper
abstract methods). Here's an example:
# main.nim
# Free Public License 1.0.0
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
# PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
import oop, math
{.this:self.}
type
Shape = ref object {.inheritable.}
Circle = ref object of Shape
radius: float
Square = ref object of Shape
width: float
Rectangle = ref object of Shape
width, height: float
# Base methods
method area(self: Shape): float {.base.} = abstract
method circumference(self: Shape): float {.base.} = abstract
method `$`(self: Shape): string {.base.} = abstract
# Circles
proc init(self: Circle, r: float) =
radius = r
method area(self: Circle): float =
radius * radius * PI
method circumference(self: Circle): float =
radius * PI * 2
method `$`(self: Circle): string =
"Circle(" & $radius & $ ")"
# Squares
proc init(self: Square, w: float) =
width = w
method area(self: Square): float =
width * width
method circumference(self: Square): float =
width * 4
method `$`(self: Square): string =
"Square(" & $width & $ ")"
# Rectangles
proc init(self: Rectangle, w, h: float) =
width = w
height = h
method area(self: Rectangle): float =
width * height
method circumference(self: Rectangle): float =
width * 2 + height * 2
method `$`(self: Rectangle): string =
"Rectangle(" & $width & ", " & $height & $ ")"
proc main =
let shapes = @[
make Circle(3.0),
make Square(5.0),
make Rectangle(6.0, 4.5)
]
for shape in shapes:
echo shape
echo "=> area ", shape.area
echo "=> circumference ", shape.circumference
main()
# oop.nim
# Free Public License 1.0.0
#
# Permission to use, copy, modify, and/or distribute this software for
# any purpose with or without fee is hereby granted.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
# AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
# DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
# PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
import macros
type AbstractMethodError* = object of Exception
template abstract* =
raise newException(AbstractMethodError, "abstract method")
macro make*(e: untyped): auto =
var tp, call: NimNode
let sym = genSym(nskVar)
case e.kind
of nnkCall:
case e[0].kind
of nnkDotExpr:
tp = e[0][0]
call = newCall(e[0][1])
add(call, sym)
for i in 1..len(e)-1:
add(call, e[i])
of nnkIdent:
tp = e[0]
call = newCall(!"init", sym)
for i in 1..len(e)-1:
add(call, e[i])
else:
error("not a constructor call")
of nnkDotExpr:
tp = e[0]
call = newCall(e[1], sym)
else:
error("not a constructor call")
expectKind(tp, nnkIdent)
result = quote do:
var `sym` = `tp`()
`call`
`sym`
when isMainModule:
import strutils
type Obj = ref object {.inheritable.}
x: int
type Obj2 = ref object of Obj
y: int
proc init(ob: Obj) =
ob.x = 1
proc init(ob: Obj, z: int) =
ob.x = z
proc fromString(ob: Obj, s: string) =
ob.x = s.parseInt
proc fromMin(ob: Obj, a, b: int) =
ob.x = min(a, b)
proc fromPair(ob: Obj2, pair: (int, int)) =
ob.x = pair[0]
ob.y = pair[1]
proc `$`(ob: Obj): string = "Obj(x: " & $ob.x & ")"
proc `$`(ob: Obj2): string = "Obj2(x: " & $ob.x & ", y: " & $ob.y & ")"
var a1 = make Obj.init
var a2 = make Obj.init(2)
var a3 = make Obj(3)
var a4 = make Obj.fromString("99")
var a5 = make Obj.fromMin(314, 2718)
var a6 = make Obj()
var a7 = make Obj2.init()
var a8 = make Obj2.fromString("314")
var a9 = make Obj2.fromPair((10, 20))
echo a1
echo a2
echo a3
echo a4
echo a5
echo a6
echo a7
echo a8
echo a9