Skip to content

Documentation

Neo edited this page May 29, 2022 · 28 revisions

class

import oolib

# create Person type
class Person:
  var
    name*: string
    age* = 0

let
  tony = Person.new("Tony")
  steve = Person.new("Steve", 100)

doAssert tony.name == "Tony"
doAssert tony.age == 0

doAssert steve.name == "Steve"
doAssert steve.age == 100

export

pub is instead of *.

example:

# `A` is exported
class pub A

# `B` is not exported
class B

member variables

class can define member variables starting with var and they can be set to default values.

class A:
  var a: int
  var b: string

class B:
  # infer types from default values
  var
    c = "default"
    d = 1.5

data constants

Data constants are constants that can be accessed from both a type and an instance. they start with const and their value must be set when a class is defined.

class MoneySymbol:
  const JPY = "¥"
  const US = "$"

constructor

class defines constructor automatically from definition of member variables in its body. Once a class is exported, a constructor is also exported.

example:

class Sword:
  var offence: int

  proc attack() =
    echo "attack!"

# `Sword.new` is automatically defined.
let sword = Sword.new(9)

When a variable has a default value, an argument of constructor has a default value just like it.

class List:
  items: seq[string] = @[]

var
  list1 = List.new(@["apple", "orange"])
  list2 = List.new()

assistance with constructor definition

class auto-inserts followings:

  • return type
  • member variables with default values as arguments of constructor
  • var self: Type in the 1st line of constructor
  • return self in the last line of constructor
class Gun:
  var
    capacity: uint
    bullets: uint
  proc `new`(capacity: uint) =
    self.capacity = capacity
    self.bullets = capacity

  proc shoot() =
    if self.bullets > 0:
      self.bullets = self.bullets - 1
    else:
      echo "Out of bullets!"

let gun = Gun.new(6)

{.noNewDef.}

Mark with {.noNewDef.} not to define constructor.

class Data {.noNewDef.}:
  var x, y: int
 
discard Data.new(1, 2) # error!

routines

class supports proc, func, method, iterator, converter, and template, with the only exception being macro.
For these, self is automatically inserted as the first argument.

omission of body

class can omit its body.

class A:
  discard
# is same as
class B

generics

Generic types are supported only in normal classes for now and cannot be used in member variables.

class A[T]:

  proc f1[T](s: seq[T]) =
    for i in s:
      echo i

let a1 = A[int].new()
let a2 = A[string].new()

a1.f1 @[4, 2, 4]
a2.f1 @["a", "b"]

inheritance

Inheritance is done as follows:

# Mark {.open.} to be inheritable
class A {.open.}

class B of A

# This will be parsed as Alias
class B(A)

# This is not inheritable
class C

# error!
class D of C

Superclass must be marked with {.open.}.

super

In methods of class, super keyword is defined to access superclass.

from typetraits import name

class A {.open.}:
  method abstractMethod {.base.} =
    echo &"Abstract method of {self.type.name}!!!"

class B of A:
  method concreteMethod =
    super.abstractMethod()
    echo &"Concrete method of {self.type.name}!!!"

distinct

example:

class Dollar(distinct int):
  proc `+`(v: Dollar): Dollar {.borrow.}
  proc `$`: string {.borrow.}

echo 100.Dollar + 50.Dollar

alias

example:

# It's same as `type A = int`
class A(int)

implementation

class can implement protocol, described later.

isClass

It returns whether a type is class or not. example:

class A

let a = A()

# Both are available
assert A.isClass()
assert a.isClass()

protocol

protocol provides tuple for interface. For now, multiple implementation is not supported.

protocol Animal:
  var scientificName: string

  proc breathe()
  proc roar()

class Cat impl Animal:
  var scientificName: string
  var name {.ignored.}: string

  proc breathe() =
    echo "breathed!"

  proc roar() =
    echo "meow!"

class Dog impl Animal:
  var scientificName: string
  var name {.ignored.}: string

  proc breathe() =
    echo "breathed!"

  proc roar() =
    echo "bark!"

let cat = Cat.new("Felis catus", "Leo").toInterface()
let dog = Dog.new("Canis lupus familiaris", "Wolf").toInterface()

cat.breathe()
cat.roar()
dog.breathe()
dog.roar()

export

pub is instead of *.

member variables

protocol can define member variables starting with var and they cannot be set to default values.

procedures

protocol can force class to implement procedures.

protocol Walkable:
  proc walk()

class Person impl Walkable:
  proc walk() = echo "Walking!"

# error!
class Robot impl Walkable:
  proc run() = echo "Running!"

{.ignored.}

Mark with {.ignored.} to ignore properties that isn't defined in protocol.

protocol SNS:
  var username: string

class Discard impl SNS:
  var username: string
  var mail {.ignored.}: string
  var password {.ignored.}: string

  proc verify() {.ignored.} =
    discard

toInterface

a class that implements a protocol has toInterface() to be converted to interface.

protocol Weapon:
  var offence: int

class Sword impl Weapon:
  var offence: int

class Hatchet impl Weapon:
  var offence: int

class Player:
  var equipment: Weapon

let sword = Sword.new(5).toInterface()
let hatchet = Hatchet.new(4).toInterface()
let player1 = Player.new(sword)
let player2 = Player.new(hatchet)

isProtocol

It returns whether a type is protocol or not. example:

protocol A:
  var val1: int

let a: A = (val1: 1)

# Both are available
assert A.isProtocol()
assert a.isProtocol()