Линейные типы

Большинство типов в YQL являются неизменяемыми, то есть выражения возвращают новые значения, а не меняют существующие.

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

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

Линейные типы доступны начиная с версии 2025.04.

Линейные типы описываются одним параметром-типом T и бывают двух видов — статически верифицируемые Linear<T> и верифицируемые во время выполнения DynamicLinear<T>.

Статически верифицируемые типы более эффективные, но имеют ограничения по композиции.

Обычно в параметре T линейного типа используется тип Resource. В этом случае пользовательские функции (UDF) могут передавать такие данные друг другу с гарантией защиты от повторного использования в запросе, что позволяет использовать более эффективную реализацию.

Линейные типы не являются сериализуемыми — их нельзя прочитать/записать в таблицы, т.е. их можно использовать только в середине выражений.

Функции, принимающие или возвращающие линейные типы, делятся на 3 класса:

  • Если линейный тип содержится в результате, но не в аргументах - это порождающая функция;
  • Если линейный тип содержится и в аргументах и в результате - это трансформирующая функция;
  • Если линейный тип содержится в аргументах, но не в результате - это поглощающая функция.

Порождающая функция обязательно принимает зависимое выражение как минимум в одном аргументе, так как можно построить из входных аргументов несколько независимых значений линейных типов.
Создавать и поглощать линейные типы рекомендуется внутри функции Block, позволяющей ввести анонимное зависимое выражение как аргумент lambda.

Правила проверки статических линейных типов Linear<T>

  • Linear типы проверяются как последняя стадия оптимизации, и, если оптимизатор устранил повторное использование выражения, то ошибки не возникает.
  • Linear тип не может быть аргументом lambda.
  • Linear тип не может возвращаться из lambda.
  • Linear тип можно использовать либо сам по себе, либо как поле в Struct/Tuple (без вложенности). При этом по возможности отслеживается индивидуальное использование полей Struct/Tuple через оператор обращения к полю (точка).

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

Правила проверки динамических линейных типов DynamicLinear<T>

  • Функция FromDynamicLinear или пользовательские функции (UDF) могут извлечь значение такого типа, но не более одного раза - иначе возникнет ошибка выполнения запроса.