Темы



Релиз языка программирования Nim 2.4.0

Коротко сгенерировано ИИ по тексту статьи
  • В Nim 2.4.0 добавили оптимизацию коротких строк SSO, включаемую через `--strings:sso`, и API для их чтения и записи.
  • Опция `--ic:on` включает параллельную и инкрементальную сборку; на 16 физических ядрах сборка компилятора Nim заняла 25 вместо 31 секунды.
  • Добавлены алгоритм YRC для циклических ссылок между потоками и типы-суммы с сопоставлением с образцом.

Представлен релиз языка системного программирования Nim 2.4.0. Nim — статически типизированный компилируемый язык программирования с синтаксисом, вдохновлённым Python, и возможностями метапрограммирования на уровне Lisp. Язык компилируется в C, C++ и JavaScript, обеспечивая производительность на уровне C при выразительности высокоуровневых языков. Код проекта поставляется под лицензией MIT.

Возможности Nim включают систему макросов, работающих на AST во время компиляции, поддержку обобщённого программирования с концептами, множественную диспетчеризацию (multiple dispatch), детерминированное управление памятью с поддержкой нескольких стратегий (ARC/ORC, refc, маркировка-и-подметание), встроенную поддержку async/await для асинхронного программирования и FFI для простой интеграции с C/C++/JavaScript. Nim позиционируется как системный язык, подходящий для разработки от встраиваемых систем до веб-серверов, с акцентом на эффективность, безопасность памяти и удобство разработки.

Основные изменения:

  • Реализован режим оптимизации коротких строк (SSO, Small-String Optimization), включаемый через опцию »--strings: sso» и приводящий к хранению небольших строк непосредственно в самом объекте, без отдельного выделения памяти в куче. Для эффективного использования этого режима предложен новый низкоуровневый API, в котором вместо «addr myString[offset]» предложены раздельные операции для чтения и записи (readRawData, readRawDataStable, beginStore и endStore). Например, при использовании нового API операции addr s[i] и unsafeAddr s[i] заменяются на вызов readRawData (s, i), а связка setLen и addr s[oldLen] заменяется на beginStore (s, newLen, start) с последующим endStore (s).

        # До: установка длины и копирование по адресу элемента строки
        result.setLen newLen
        copyMem(addr result[oldLen], buf, buflen)
    
        # После: beginStore устанавливает длину, обеспечивает уникальное
        # владение и возвращает указатель для записи; endStore завершает запись
        copyMem(beginStore(result, newLen, oldLen), buf, buflen)
        endStore(result)
    
  • Реализована поддержка параллельной и инкрементальной сборки, активируемой через опцию »--ic: on». Распараллеливание реализовано на основе многопроцессности, а не многопоточности, поэтому макросы, использующие глобальные переменные .compileTime, могут потребовать доработки для ускорения сборки. Ускорение наблюдается не только при повторных пересборках, но и при первой сборке за счёт распараллеливания. Например, сборка компилятора Nim на машине с 16 физическими ядрами при использовании опции »--ic: on» сократилась с 31 до 25 секунд.

  • Добавлен новый алгоритм управления памятью YRC, активируемый опцией »--mm: yrc» и обеспечивающий корректную обработку циклических ссылок, пересекающих границы потоков. YRC предоставляет тот же API, что и ORC, но помимо возможностей последнего обеспечивает потокобезопасность. Для ациклических данных применяется атомарный подсчёт ссылок, а для циклических — барьер записи (write barrier), который активируется только при присваивании указателей. При этом в тесте orcbench YRC примерно в два раза медленнее ORC и потребляет вдвое больше памяти.

  • Поддержка типов-сумм (sum types), при объявлении которых применяется сопоставление с образцом.
        type
          Node = ref object
            case
            of IntLit: intVal: int
            of FloatLit: floatVal: float
            of StringLit: strVal: string
            of AddOp, SubOp:
              leftOp, rightOp: Node
            of IfStmt:
              condition, thenPart, elsePart: Node
    

    Имя ветви служит конструктором с именованными аргументами:

        let n = AddOp(leftOp: IntLit(intVal: 40), rightOp: IntLit(intVal: 2))
    

    Поддерживаются обобщённые типы-сумм (generic), в которых конкретный экземпляр выводится из значений полей или из ожидаемого типа:

        type
          Opt[T] = object
            case
            of None: discard
            of Some: val: T
    
        let a = Some(val: "abc")      # Opt[string]
        let b: Opt[int] = None()      # ожидаемый тип выбирает экземпляр
    

    Доступ к полям осуществляется исключительно через сопоставление с образцом, поэтому обращение к полю чужой ветви (FieldDefect) невозможно. Поля привязываются к именам, следующим за именем ветви:

        proc eval(n: Node): int =
          case n
          of IntLit(v): v                    # v привязано к intVal
          of AddOp(a, b): eval(a) + eval(b)  # a, b — leftOp, rightOp
          of SubOp(a, b): eval(a) - eval(b)
          else: raiseAssert "not an arithmetic expression"
    
  • Добавлен экспериментальный модификатор «owned» для управления памятью на основе явного владения без использования сборщика мусора, активируемый при указании опции »--experimental: ownedRefs». Типы «owned ref T» и замыкания «owned» гарантируют наличие единственного владельца у объекта. Подобные объекты нельзя копировать и можно только перемещать, а при выхода из области видимости они автоматически уничтожаются.

  • Добавлена прагма »{.cyclic.}» для обработки циклического импорта модулей, ссылающихся друг на друга, которая позволяет связывать модули напрямую без выноса типов в отдельный файл и избавляет от необходимости подбирать строгий порядок объявлений в коде.



Источник: http://www.opennet.ru/opennews/art.shtml? num=66570

© OpenNet