Все фичи в языках программирования условно делятся на три следующих класса:

  1. Фичи, вокруг которых, в сущности, построен язык — поэтому постфактум добавить их невозможно. Таковы, например, ленивость в Haskell, проверка заимствований в Rust, т.д.

  2. Фичи, значительно влияющие на работу с языком. Их можно добавить не сразу, но в таком случае для их внедрения потребовалось бы серьёзно поработать над проектированием, инженерией и планированием. Я бы отнёс к этой категории сопоставление с образцом, алгебраические типы данных и асинхронность.

  3. Фичи «для дополнительного комфорта», добавить которые не так сложно, и при отсутствии которых язык особенно не меняется. Зачастую сюда относится синтаксический сахар, например, сцеплённые вычислители (chained evaluators) в Python (if 2 <= x < 10).

Большая часть работы по теории языков программирования и проектированию языков программирования касается аспектов (1) и (2), так как именно они наиболее важны, но лично я глубоко увлекаюсь фичами типа (3). Поскольку эти фичи такие мелкие, именно они наиболее активно перетекают из языка в язык, ведь добавить их можно совсем «малой кровью». Сам я много времени провёл за изучением нишевых малопонятных языков, и за этим встречал множество крутых фич из третьей категории — таких, с которыми вы, возможно, никогда не сталкивались. Расскажу о некоторых из них!

❯ Представления чисел

Есть множество мелочей, упрощающих работу с числами. Во-первых, можно добавлять разделительные знаки, что уже делается во многих языках. Можно написать не 10000500, а, например, 10_000_500 или 1_00_00_500, если вы индус. Также вполне подойдёт 1e3 вместо 1000.

Ещё более интересные качественные улуч��ения работы с числами предусмотрены в языке J. В естественных науках и математике зачастую приходится оперировать уравнениями со степенями и корнями π. В J предусмотрен стандартизированный формат для чисел xπ^y, записываемый как {x}p{y}. Например, можно записать 5*sqrt(π) как 5p0.5. Также есть x для степеней e и r, чтобы работать с точными рациональными числами, например, ((2r3 + 1) = 5r3).

❯ Сбалансированные строковые литералы

В Lua при помощи нотации [[]] можно записывать необработанные многострочные последовательности символов:

[[
  Alice said "Bob said 'hi'".
]]

Многострочные литералы есть в большинстве языков программирования, но фишка Lua в том, что здесь начало и конец литерала обозначаются разными символами. Так решается ужасающая проблема «невкладываемых кавычек», присущая строковым литералам. Кроме того, не приходится экранировать все ваши литералы по принципу \s. При работе с neovim мне требуется, чтобы строка [[\\]] буквально означала \\. При экранировании в данном случае получилось бы "\\\\" или что-то подобное, ой.

❯ Обобщённый синтаксис обновлений

Мне он попался в Noulith, и я сразу же в него влюбился:

Если вы когда-либо хотели при поиске какого-то максимального значения в некотором сложном цикле обойтись записью x max= y, то эта фича – для вас. Она применима практически с любой функцией.

Иными словами, x max= y ⇔ x = max(x, y). Вполне можно себе представить, как это расширить до таких вещей как text sub= (regex, replacement), что закрывало бы массу мелких задач по фильтрации и латанию данных, которыми мне приходится заниматься.

❯ Минута славы языка Chapel

Chapel — это язык для высокопроизводительных вычислений, используемый для прогона очень быстрых алгоритмов на сотнях или тысячах процессоров. В нём куча фич из категорий (1) и (2), которых я более нигде не видел, и вообще этот язык показался мне невероятно интересным. Даже ещё не зная его, я нашёл в его документации несколько штук категории (3), которые теперь очень хочу увидеть в других языках.

Во-первых, там есть ключевое слово config. Если написать config var n=1, то компилятор автоматически добавит к двоичному файлу флаг --n. Поскольку я 1) люблю, чтобы мои программы хорошо конфигурировались и 2) терпеть не могу заниматься первичной подготовкой CLI-библиотек, этот дёшевый и сердитый способ добавлять флаги к одиночным переменным кажется мне безусловно выигрышным.

Во-вторых, можно записать последовательность 1, 2, … n-1 как 1..<n. Это элегантное расширение для стандартного оператора .., используемого в таких языках как Ruby и TLA+.

В-третьих— и это гораздо более сильный аргумент— в Chapel у вас есть «продвижение» (promotion), оно же «расширение» типов — это автоматический подъём типа. Суть этой операции в следующем: если у вас есть функция типа a -> a, то Chapel позволяет вам вызывать её и с массивами, возвращая отображённы�� массив. Таким образом, если f(x) = 2*x, то f([1, 2, 3]) = [2, 4, 6]. Кроме того, такая операция полностью типобезопасна. Такого же результата в других языках можно достичь при помощи lift или map, но очень удобно реализовать такую возможность нативно.

(Здесь Chapel проявляет дополнительную гибкость: он автоматически распараллеливает вычисления. Но это определённо выходит за рамки категории (3)).

Это лишь некоторые классные фичи Chapel, и здесь я даже не затрагиваю по-настоящему фундаментальных вещей. Всем, кто интересуется теорией языков программирования или научными вычислениями решительно рекомендую попробовать этот язык.

❯ Литералы дат

В языке Frink предусмотрен особый синтаксис для значений, означающих даты. Можно записать # 2001-08-12 #, и это будет означать дату 2001-08-12, а не писать чего-то столь неудобного как Date(2001, 8, 12) — тем самым сразу получив баг, поскольку месяцы начинаются с 0 (а дни — нет).

❯ Расширенные блоки параметров

В функциях Powershell может явно присутствовать блок Param, в котором определяются атрибуты для каждого параметра функции — например, значения по умолчанию, справочная документация, ограничения валидации и т.д. Поэтому можно не писать fun f(str path = "/", int x), а сделать нечто подобное (далее – на псевдокоде):

fun f {
  params (
    [default = "/"]
    [help = "The path to your file"]
    [mandatory]
    [str]path
  , [optional][int] x
  )
}

Теперь у вас получилась конструкция, гораздо более подходящая для языка оболочки, где у вас множество опциональных флагов, переключателей и псевдонимов. Но я считаю, что такая фича может быть по-настоящему полезна и в компилируемом языке. Во-первых, с ней становится проще добавлять контракты, действующие на уровне переменных. Во-вторых, представьте, как хорошо было бы абстрагировать блоки параметров. Если присмотреться к таким вещам как функции numpy, оказывается, что во многих из них используются одни и те же определения параметров. Что, если бы можно было написать def log(standard-exp-params), а не выписывать всякий раз каждую из них в отдельности?

❯ Шашлычный регистр

Встречается в большинстве lisp-подобных языков. Можно использовать не только названия two_words или TwoWords, но и two-words. Это проще пишется и проще читается. Естественно, за пределами lisp-подобных языков это невозможно, поскольку в них есть инфиксный минус, и возникает двусмысленность: x-y — это выражение x минус y или вызов функции x-y? Правда, мне такой компромисс не нравится. Часто ли вы пользуетесь – и часто ли пишете многословные функции? Просто условимся, что x-y — это всегда функция, а если требуется прибегнуть к математике, то можно воспользоваться пробелами, как это делают все.

(Учитывайте, что эту возможность не получится добавить в уже существующие языки, не поломав в них всё, но, может быть, такой вариант стоит держать в уме, если вы создаёте новый язык?)

❯ Символы

В Ruby есть особый тип данных под названием symbol, который записывается так: :this. Символ сравнивает строку с самим собой и больше ни для чего не используется. Он заменяет однословные строки. Таким образом, можно вместо  dict["employee_id"] написать dict[:employee_id].

Символы удобны именно потому, что упрощают работу со строками. В большинстве языков строки могут выражать множество различных сущностей: токены, текст, структурированные данные, код, т.д. Если вы видите строку "book", то без контекста непонятно, что это такое: ключ из словаря, или текстовое поле, в котором "book", или тривиальные CSV, или что-то ещё. Работая с символами, можно, как минимум, исключить первый случай, поскольку он записывался бы как :book.

❯ Специальный синтаксис для тестов

В языке D есть специальные блоки модульных тестов для функций и P-мониторы. Притом, что целесообразно держать всё тестирование в рамках библиотечного кода, в больших программных проектах тестирование является настолько универсальным, что было бы хорошо обеспечить ему и поддержку на уровне синтаксиса.

Как бы то ни было, я не думаю, что всё это можно было бы легко добавить в произвольный язык, и что эти фичи не спровоцировали бы нисходящих изменений. Но они, как минимум, кажутся более независимыми от семантики существующих языков, чем фичи категории 2, которые зачастую добавляются постфактум (и это приносит немало пользы). Таким образом, описанные здесь фичи проще распространять от языка к языку. Конечно, за исключением шашлычного регистра. Мир слишком порочен.


Новости, обзоры продуктов и конкурсы от команды Timeweb.Cloud — в нашем Telegram-канале 

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


  1. domix32
    12.01.2026 15:02

    поддержку P-мониторов вроде можно занести в языки посредством специальных комментариев (1, 2). Только спеки тоже придётся программировать.

    А из фичей конечно хотелось бы быстрые касты типов, как в jai.

    foo : fn(x: i32, y: u12) { /* impl here */}
    
    a : i32 = 34;
    b : i32 = 35;
    
    foo(a,b);         // oh noes. i32 не вмещается в u12
    foo(a, xx b);     // привести тип автоматически
    foo(a, b as u12); // ну или привести явно как в rust

    инты произвольной длины как в Zig тоже кстати полезная штука.


  1. rsashka
    12.01.2026 15:02

    Фичи, вокруг которых, в сущности, построен язык — поэтому постфактум добавить их невозможно. Таковы, например, ленивость в Haskell, проверка заимствований в Rust, т.д.

    Очень сильно сказано, но в корне не верно.

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


  1. akardapolov
    12.01.2026 15:02

    Можно использовать не только названия two_words или TwoWords, но и two-words. Это проще пишется и проще читается.

    А проще пишется и читается это про что? Про нижнее подчеркивание или тире?

    Лично мне удобнее - тире, для нижнего подчеркивания нужно 2 нажатия клавиш, для тире - только одно.


  1. bromzh
    12.01.2026 15:02

    Микрофичи, которые сделают ваш язык write-only