особенности ООП - ponyatov/nimbook GitHub Wiki

особенности ООП

  • в Nim нет инкапсуляции:
    • определение типа (класса) и процедуры (метода) описываются отдельно, и могут находится в полностью независимых модулях
    • любая процедура автоматически является методом для типа ёё первого аргумента
    • в своём коде вы можете абсолютно свободно (пере)определять методы для любых типов из сторонних библиотек

Определение объекта в Nim полностью эквивалентно структуре в языке Си, и именно так передается в C-код через FFI. Новые типы определяются синтаксической конструкцией type. Определение объекта может быть помещено в одной строке с ключевым словом type или в виде блока под ним:

type
  Person = object
    name: string
    age: int

В type-блоке могут определяться несколько типов, и именно так желательно собирать связанные типы (структура кода очень похожа на Паскаль). Как и процедуры, типы должны быть сначала определены над кодом, в котором они используются.

Переменная, использующая тип Person, объявляется так же, как и любая другая переменная:

var person: Person

Типы принято именовать с большой буквы, инстансы (переменные) с маленькой (как в Smalltalk).

Использовать неинициализированные переменные считается очень плохим стилем, поэтому при возможности объявляйте инициализированные переменные:

var person = Person(name: "Neo", age: 28)

Вы можете указать все, некоторые или ни одно из полей. Для object-типов память размещается в стеке. Освобождение памяти для них самое простое -- удаляется все, что выходит за границы текущего вызова процедуры.

Когда вы определяете новую переменную, вы не можете изменить где для неё распределяется память -- в стеке или в куче. Если вы хотите выделять переменные в куче, нужно изменить само определение типа: ref object объекты распределяются в куче. Наличие ref намекает на использования подсчета ссылок для определения тех объектов, которые могут быть удалены из памяти, так как не используются в других объектах. Объекты с циклическими ссылками дочищает сборщик мусора.

Типы, определенные с помощью ключевого слова ref, называются ссылочными типами. Когда экземпляр ссылочного типа передается в качестве параметра в процедуру, вместо передачи копии объекта по значению, он передается по ссылке. Это позволяет вам изменять исходный объект, соответствующий переданному параметру процедуры, как изнутри вашей процедуры, так и снаружи (в т.ч. асинхронно). non-ref объекты, передаваемые в качестве параметра в процедуру, являются неизменяемыми, так как все операции выполняются с копией объекта на стеке, и будут выброшены при выходе из процедуры вместе с освобождением памяти этой копии.

Если требуется работать сразу с ref и non-ref вариантами, предлагается следующий паттерн с наследованием:

type
  PersonObj = object
    name: string
    age: int
  PersonRef = ref PersonObj

по соглашениям для non-ref используется суффикс типа Obj и от него наследуюется ссылочный тип с суффиксом Ref.

Для обращения к полям ref-объектов никакой специальный синтаксис не требуется:

proc setName(person: PersonObj) =
  let x = person.name
  # ошибка: модификация иммутабельного нессылочного параметра
  # nim compiler Error: 'person.name' cannot be assigned to
  person.name = "George"

proc setName(person: PersonRef) =
  person.name = "George"

наследование

Variant-типы (tagged union)

настоящее чистое ООП