👑

Nimでclass構文が使えるパッケージをつくった

2021/08/23に公開

はじめに

こんにちは、Neoと申します。
オブジェクト指向プログラミングのためのNimbleパッケージをつくったので、紹介します。

つくったもの

「OOlib(おーおーりぶ)」といいます。
https://github.com/Glasses-Neo/OOlib

install

nimble install oolib

使い方

class

基本的には、他の言語のclassと同じように使えます。

class Person:
  var name: string
  var age: int = 0

proc happyBirthday() =
  inc self.age

let
  p1 = Person.new("Sam")
  p2 = Person.new("Steve", "100")

公開

pubでそのクラスを公開できます。
メンバー変数、プロシージャなどは通常と同じく*です。

class pub A:
  var a*, b: int

  proc inc* =
    inc a
    inc b

変数

メンバー変数はvarで定義し、デフォルト値の設定ができます。

class A:
  var a: int
  var b: string
  var c, d = true # 型推論が可能

データ定数

データ定数は、型とインスタンスの両方からアクセスできる定数です。constで始まり、値はクラスの定義時に決定される必要があります。

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

コンストラクタ

コンストラクタは、クラス内の変数定義をもとに自動で定義されます。コンストラクタには、クラスの公開/非公開が自動で反映されます。

class Sword:
  var offence: int

  proc attack() =
    echo "attack!"

# `Sword.new`が自動で定義された
let sword = Sword.new(9)

プロシージャ

プロシージャ系は、proc, func, method, iterator, converter, templateなどmacro以外のすべてに対応しています。また、自動で第1引数にそのクラスの型でselfが追加されます。(VScodeでちゃんと補完も効く)

class A:
  var
    name: string
    age: int = 0

  proc happyBirthday =
    inc self.age

  func addAge(x: int): int =
    result = self.age + x

コンストラクター

コンストラクターは自動定義と自前で定義する方法の2種類があります。
デフォルト値を設定せず、かつ自前で定義した場合は、pythonの__init__とよく似た挙動になります。
デフォルト値を設定し、かつ自前で定義した場合は、デフォルト値が設定されているメンバー変数だけコンストラクターの引数として挿入されます。

class A:
  var
    a: int
    b: string

class B:
  var
    a: int
    b: string

  proc `new`(str: string) =
    self.a = str.len
    self.b = str

class C:
  var
    a: int
    b: string = "default"

class D:
  var
    a: int
    b: string = "default"

  proc `new`() =
    # `b: string = "default"`が引数として自動で挿入される
    self.a = b.len

let
  a = newA(1, "str")
  b = newB("string")
  c1 = newC(2, "str")
  c2 = newC(3)
  d1 = newD(4, "str")
  d2 = newD(5)

継承

class サブクラス of スーパークラスで継承ができます。継承するためには、スーパークラスに{.open.}プラグマを付けなければいけません。
method内には、スーパークラスにアクセスするためのsuperが定義されます。また、super.メソッド()とアクセスしてもクラッシュを起こさないようになっています。

class A {.open.}:
  var name: string

  proc `$`*: string = self.name

  method abstractMethod {.base.} =
    echo &"Abstract method of {self.name}!!!"

class B of A:
  # 実装の関係で、サブクラスはコンストラクタの自動定義が不可
  proc `new` =
    self.name = name

  method concreteMethod =
    super.abstractMethod()
    echo &"Concrete method of {self.name}!!!"

おわりに

現在検討している機能は、オブジェクト以外の継承、TypeScriptのPickに相当するマクロなどです。
最後までお読みいただきありがとうございました。リポジトリにstarしていただけると嬉しいです。

GitHubで編集を提案

Discussion