Логотип языка Nim

Всем привет! В данной статье я постараюсь рассказать, что такое generic процедуры и converter’ы в Nim (и показать примеры их использования)

Что такое Nim? Nim – компилируемый (в C, C++, Objective C и JS) высокоуровневый язык программирования со сборщиком мусора, имеющий три основных цели (в порядке приоритета): производительность, выразительность, элегантность. Официальный сайт языка, репозиторий на GitHub.
Также в Nim достаточно развито метапрограммирование (дженерики, шаблоны, макросы).

Для начала я покажу, как выглядит процедура, которая имеет один аргумент типа int, и возвращает тоже int:

proc plusOne(arg: int): int = 
  return arg + 1
echo plusOne(5)  # Выведет 6

Как я думаю, тут всё предельно ясно (прибавляем число 1 к аргументу arg типа int и возвращаем результат)

Дженерики в Nim — это процедуры, которые могут принимать несколько типов (компилятор сделает отдельную версию процедуры для каждого типа, который использовался с данной процедурой).

1 пример — обычный дженерик


Этот пример выводит длину объекта, если для данного объекта имеется процедура len (почти что полный аналог __len__ в Python):

proc tryLen[T](something: T) = 
  when compiles(something.len):  # something.len это тоже самое, что len(something)
    echo something.len
  else:
    echo "У этого типа не объявлена процедура `len`"

# Объявим тип нового объекта, у которого не будет процедуры `len` (так как мы её не объявляли)
type MyObject = object
# Создадим сам объект
let myObj = MyObject()
tryLen([1, 2, 3])  # Выведет 3
tryLen("Hello world!")  # Выведет 12
tryLen(myObj)  # Выведет "У этого типа не объявлена процедура `len`"

Этот пример намного сложнее предыдущего, я постараюсь кратко объяснить, что тут происходит:

Для начала мы объявляем саму процедуру tryLen, которая принимает аргумент something типа T (T — это чаще всего используемое название для неопределённого типа, вместо T можно написать abcd, и всё будет работать точно так же).

Затем мы используем специальное условие when compiles (это аналог if, но условие должно быть известно во время компиляции, и сам when в скомпилированный код не попадает). Если это условие выполняется для данного типа — выводим результат процедуры len для данного аргумента, если не выполняется — выводим сообщение.

Затем мы создаём объект типа MyObject, и применяем tryLen к массиву [1, 2, 3], строке «Hello world!», и нашему объекту.

2 пример — конвертер


Он служит для неявного конвертирования одного типа в другой (но он не особо приветствуется самими разработчиками языка, так как в этом случае всё-таки «явное лучше неявного»).

В данном примере мы сделаем конвертер, который конвертирует наш тип объекта MyObject в число (в данном случае — просто 1):

type MyObject = object
let myObj = MyObject()

# Если процедура или конвертер маленькие, то можно сразу написать возвращаемое значение без return
# Имя конвертера не играет какой-либо особенной роли
converter toInt(b: MyObject): int = 1
# Конвертер можно вызвать явно (однако в этом случае лучше сделать обычную процедуру)
echo myObj.toInt + 1  # Выведет 2
# Или он сам может вызываться неявно:
echo myObj + 1  # Тоже выведет 2, так как toInt неявно конвертировал myObj в число 1

Использование конвертеров — спорная тема (в стандартной библиотеке языка они почти не используются), но я отношусь к ним нейтрально.

Последний пример — дженерик конвертер


Да, звучит страшно, но на самом деле всё не так сложно. С помощью него мы сможем сделать Nim чуть более похожим на Python (а именно — неявно преобразовывать некоторые типы к bool)

converter toBool[T](arg: T): bool = 
  # Если для данного типа аргумента имеется процедура len
  when compiles(arg.len):
    arg.len > 0
  # Если для данного типа имеется процедура `>`
  elif compiles(arg > 0):
    arg > 0


if [1, 2, 3]:  # Длина массива
  echo "True!"
if @[1, 2, 3]:  # Длина последовательности
  echo "True too!"
if "":  # Пустая строка
  echo "No :("
if 5:  # Integer
  echo "Nice number!"
if 0.0001:  # Float
  echo "Floats are nice too!"

Спасибо за чтение! Я надеюсь, что вы смогли почерпнуть для себя что-то новое.

Источники
Мануал
Википедия
А также пользователи Nim, которые мне подсказывали решение различных проблем.
Поделиться с друзьями
-->

Комментарии (7)


  1. antonksa
    19.07.2017 13:53
    +3

    Спасибо! Если будет цикл статей по Ниму — я вообще буду счастлив!


  1. zolern
    19.07.2017 16:59
    +2

    Плюс один за цикл статей про Nim. Думаю очень интересно будеть прочитать про Nim FFI; тема — особено что касается практики — не слишком хорошо озвучена, а того стоит.


    Сам из плюсах и люблю их за скорость и универсальность, нравится и Python за его елегантность, но так и не пересел с плюсах на Python; такое ощущение, что как-то неправилно это менять скорость за елегантность. А потом столкнулся с Nim и это — скажу я вам — была любовь с первого взгляда.


    1. lega
      19.07.2017 18:41
      +1

      но так и не пересел с плюсах на Python
      Дак они для разного, я использую и то и то.


    1. Ockonal
      20.07.2017 01:11
      +1

      Пробовали Rust?


      1. zolern
        20.07.2017 15:04

        Пробовал. Не понравился.


  1. zolern
    19.07.2017 19:58

    Ну, у меня Python банально не взлетел для моих задач, вот и пришлось продолжать жрать кактуС++ :)


    Сейчас пользуюсь Nim и доволен как слон.


  1. FUNNYDMAN
    21.07.2017 13:58

    Спасибо за публикацию. Очень познавательно!