Spec-Zone.ru › OCaml
☰Язык OCaml
  • Язык OCaml
  • Расширения языка

Глава 12 Расширения языка

12 Атрибуты

  • 12.1 Встроенные атрибуты

(Добавлены в OCaml 4.02; инфиксные формы записи для конструкций, отличных от выражений, добавлены в 4.03)

Атрибуты — это «декорации» синтаксического дерева, которые в основном игнорируются проверкой типов, но могут использоваться внешними инструментами. Атрибут состоит из идентификатора и полезной нагрузки, которая может быть структурой, выражением типа (с префиксом :), сигнатурой (с префиксом :) или шаблоном (с префиксом ?), за которым при необходимости следует условие when:

attr-id ::= lowercase-ident
∣ capitalized-ident
∣ attr-id . attr-id
attr-payload ::= [ module-items ]
∣ : typexpr
∣ : [ specification ]
∣ ? pattern [when expr]

Первая форма атрибутов присоединяется с помощью постфиксной записи к «алгебраическим» категориям:

attribute ::= [@ attr-id attr-payload ]
expr ::= ...
∣ expr attribute
typexpr ::= ...
∣ typexpr attribute
pattern ::= ...
∣ pattern attribute
module-expr ::= ...
∣ module-expr attribute
module-type ::= ...
∣ module-type attribute
class-expr ::= ...
∣ class-expr attribute
class-type ::= ...
∣ class-type attribute

Эту форму атрибутов также можно вставлять после `tag-name в выражениях полиморфных вариантных типов (tag-spec-first, tag-spec, tag-spec-full) или после method-name в method-type.

Та же синтаксическая форма используется для присоединения атрибутов к меткам и конструкторам в объявлениях типов:

field-decl ::= [mutable] field-name : poly-typexpr { attribute }
constr-decl ::= (constr-name ∣ ()) [ of constr-args ] { attribute }

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

Вторая форма атрибутов присоединяется к «блокам», например объявлениям типов, полям классов и т. д.:

item-attribute ::= [@@ attr-id attr-payload ]
typedef ::= ...
∣ typedef item-attribute
exception-definition ::= exception constr-decl
∣ exception constr-name = constr
module-items ::= [;;] ( definition ∣ expr { item-attribute } ) { [;;] definition ∣ ;; expr { item-attribute } } [;;]
class-binding ::= ...
∣ class-binding item-attribute
class-spec ::= ...
∣ class-spec item-attribute
classtype-def ::= ...
∣ classtype-def item-attribute
let-binding ::= ...
∣ let-binding item-attribute
definition ::= let [rec] let-binding { and let-binding }
∣ external value-name : typexpr = external-declaration { item-attribute }
∣ type-definition
∣ exception-definition { item-attribute }
∣ class-definition
∣ classtype-definition
∣ module module-name { ( module-name : module-type ) } [ : module-type ] = module-expr { item-attribute }
∣ module type modtype-name = module-type { item-attribute }
∣ open module-path { item-attribute }
∣ include module-expr { item-attribute }
∣ module rec module-name : module-type = module-expr { item-attribute } { and module-name : module-type = module-expr { item-attribute } }
specification ::= val value-name : typexpr { item-attribute }
∣ external value-name : typexpr = external-declaration { item-attribute }
∣ type-definition
∣ exception constr-decl { item-attribute }
∣ class-specification
∣ classtype-definition
∣ module module-name : module-type { item-attribute }
∣ module module-name { ( module-name : module-type ) } : module-type { item-attribute }
∣ module type modtype-name { item-attribute }
∣ module type modtype-name = module-type { item-attribute }
∣ open module-path { item-attribute }
∣ include module-type { item-attribute }
class-field-spec ::= ...
∣ class-field-spec item-attribute
class-field ::= ...
∣ class-field item-attribute

Третья форма атрибутов встречается как самостоятельные элементы структуры или сигнатуры в подъязыках модулей и классов. Она не присоединяется к какому-либо определённому узлу синтаксического дерева:

floating-attribute ::= [@@@ attr-id attr-payload ]
definition ::= ...
∣ floating-attribute
specification ::= ...
∣ floating-attribute
class-field-spec ::= ...
∣ floating-attribute
class-field ::= ...
∣ floating-attribute

(Примечание: вопреки описанию в приведённой выше грамматике, к этим плавающим атрибутам нельзя присоединять item-attributes в class-field-spec и class-field.)

Также можно указывать атрибуты с помощью инфиксного синтаксиса. Например:

let[@foo] x = 2 in x + 1          === (let x = 2 [@@foo] in x + 1)
begin[@foo][@bar x] ... end       === (begin ... end)[@foo][@bar x]
module[@foo] M = ...              === module M = ... [@@foo]
type[@foo] t = T                  === type t = T [@@foo]
method[@foo] m = ...              === method m = ... [@@foo]

Для let атрибуты применяются к каждому связыванию:

let[@foo] x = 2 and y = 3 in x + y === (let x = 2 [@@foo] and y = 3 in x + y)
let[@foo] x = 2
and[@bar] y = 3 in x + y           === (let x = 2 [@@foo] and y = 3 [@@bar] in x + y)

12.1 Встроенные атрибуты

Некоторые атрибуты распознаются компилятором:

  • ocaml.warning или warning, со строковым литералом в качестве полезной нагрузки. Этот атрибут можно использовать как плавающий атрибут в сигнатуре / структуре / объектном типе. Строка разбирается и действует так же, как параметр командной строки -w, в области действия от атрибута до конца текущей сигнатуры / структуры / объектного типа. Атрибут также можно присоединить к любому синтаксическому элементу, поддерживающему атрибуты (например, выражению или выражению типа); в этом случае его область действия ограничена этим элементом. Обратите внимание, что область действия, применяемая для конкретного предупреждения, определена неоднозначно. Это зависит от реализации и может меняться между версиями. Некоторые предупреждения вообще не контролируются атрибутом ocaml.warning (например, предупреждения 1, 2, 14, 29 и 50).
  • ocaml.warnerror или warnerror, со строковым литералом в качестве полезной нагрузки. Действует так же, как ocaml.warning, для параметра командной строки -warn-error.
  • ocaml.alert или alert: см. раздел 12.21.
  • ocaml.deprecated или deprecated: псевдоним предупреждения deprecated, см. раздел 12.21.
  • ocaml.deprecated_mutable или deprecated_mutable. Может применяться к изменяемому полю записи. Если впоследствии это поле используется для изменения значения (с помощью expr.l <- expr), будет выдано предупреждение deprecated. Если полезная нагрузка атрибута — строковый литерал, текст будет включён в сообщение предупреждения.
  • ocaml.ppwarning или ppwarning, в любом контексте, со строковым литералом в качестве полезной нагрузки. Компилятор сообщает этот текст как предупреждение (22) (в настоящее время местоположение предупреждения совпадает с местоположением строковой полезной нагрузки). Это полезно прежде всего для препроцессоров, которым нужно сообщать пользователю о предупреждениях. Также с его помощью можно явно пометить участок кода для дальнейшей проверки.
  • ocaml.warn_on_literal_pattern или warn_on_literal_pattern помечают конструкторы в определении типа. После этого выдается предупреждение (52), если сопоставление с образцом для этого конструктора использует константный литерал в качестве аргумента. Этот атрибут обозначает конструкторы, аргумент которых носит исключительно информационный характер и может измениться в будущем. Поэтому сопоставление с образцом для этого аргумента с использованием константного литерала ненадёжно. Например, все встроенные конструкторы исключений помечены атрибутом warn_on_literal_pattern. Обратите внимание: из-за ограничения реализации это предупреждение (52) срабатывает только для конструкторов с одним аргументом.
  • ocaml.tailcall или tailcall можно применить к вызову функции, чтобы проверить, оптимизирован ли вызов как хвостовой. Если это не так, выдается предупреждение (51).
  • ocaml.inline или inline принимают в качестве полезной нагрузки never, always или ничего и применяются к определению функции или функтора. Если полезная нагрузка не указана, по умолчанию используется значение always. Эта полезная нагрузка определяет, когда следует встраивать вызовы аннотированных функций.
  • ocaml.inlined или inlined можно применить к любому вызову функции или функтора, чтобы проверить, встроен ли вызов компилятором. Если вызов не встроен, выдается предупреждение (55).
  • ocaml.noalloc, ocaml.unboxed и ocaml.untagged или noalloc, unboxed и untagged можно использовать в объявлениях внешних функций для более точной настройки интерфейса между C и OCaml. Подробнее см. в разделе 23.11.
  • ocaml.immediate или immediate, применённый к абстрактному типу, помечает его как тип с непоинтерной реализацией (например, int, bool, char или перечислимые типы). Изменение таких непосредственных типов не активирует барьер записи сборщика мусора, что может значительно повысить производительность программ, активно использующих изменяемое состояние.
  • ocaml.immediate64 или immediate64, применённый к абстрактному типу, помечает его как тип с непоинтерной реализацией на 64-разрядных платформах. Для других платформ никаких предположений не делается. Чтобы создать тип с атрибутом immediate64, необходимо использовать функтор Sys.Immediate64.Make.
  • ocaml.unboxed или unboxed можно использовать в определении типа, если тип представляет собой запись с одним полем или конкретный тип с одним конструктором, имеющим один аргумент. Этот атрибут указывает компилятору оптимизировать представление типа, удалив блок, представляющий запись или конструктор (то есть значение этого типа физически совпадает со своим аргументом). Для GADT действует дополнительное ограничение: аргумент не должен быть экзистенциальной переменной, представленной экзистенциальной переменной типа, или абстрактным конструктором типа, применённым к экзистенциальной переменной типа.
  • ocaml.boxed или boxed можно использовать в определениях типов в значении, противоположном ocaml.unboxed: сохранять неоптимизированное представление типа. Если аннотация отсутствует, по умолчанию сейчас используется boxed, но в будущем это может измениться.
  • ocaml.local или local принимают в качестве полезной нагрузки never, always, maybe или ничего и применяются к определению функции. Если полезная нагрузка не указана, по умолчанию используется значение always. Атрибут управляет оптимизацией, при которой функция компилируется в статическое продолжение. В отличие от встраивания, эта оптимизация не дублирует тело функции. Она возможна, когда все ссылки на функцию являются вызовами со всеми аргументами и используют одно и то же продолжение (например, когда возвращаемое значение используется в нескольких ветвях сопоставления с образцом). Значение never отключает оптимизацию, always указывает, что оптимизация должна применяться (иначе выдается предупреждение 55), а maybe позволяет применять оптимизацию, когда это возможно (таково поведение по умолчанию, если атрибут не указан). Оптимизация неявно отключается при использовании байткод-компилятора в режиме отладки (-g), а также для функций, помеченных атрибутом ocaml.inline always или ocaml.unrolled, которые имеют приоритет над ocaml.local.
  • ocaml.poll или poll со значением error в качестве полезной нагрузки, применённые к определению функции, приводят к ошибке всякий раз, когда компилятор вставляет в тело аннотированной функции точку опроса во время выполнения.
  • ocaml.remove_aliases или remove_aliases, указанный в выражении сигнатуры module type of или ограничении with module, предписывает проверке типов удалять псевдонимы модулей из результирующей сигнатуры.
  • ocaml.atomic или atomic в определении поля записи помечает это поле как атомарное. Подробнее см. в разделе 9.7.2.
module X = struct
  [@@@warning "+9"]  (* locally enable warning 9 in this structure *)
  …
end
[@@deprecated "Please use module 'Y' instead."]

let x = begin[@warning "+9"] […] end

type t = A | B
  [@@deprecated "Please use type 's' instead."]
let fires_warning_22 x =
  assert (x >= 0) [@ppwarning "TODO: remove this later"]

Warning 22 [preprocessor]: TODO: remove this later
let rec is_a_tail_call = function
  | [] -> ()
  | _ :: q -> (is_a_tail_call[@tailcall]) q

let rec not_a_tail_call = function
  | [] -> []
  | x :: q -> x :: (not_a_tail_call[@tailcall]) q

Warning 51 [wrong-tailcall-expectation]: expected tailcall
let f x = x [@@inline]

let () = (f[@inlined]) ()
type fragile =
  | Int of int [@warn_on_literal_pattern]
  | String of string [@warn_on_literal_pattern]
let fragile_match_1 = function
| Int 0 -> ()
| _ -> ()

Warning 52 [fragile-literal-pattern]: Code should not depend on the actual
  values of this constructor's arguments.
  They are only for information and may change in future versions.
  (see manual section 13.5.3)

val fragile_match_1 : fragile -> unit = 
let fragile_match_2 = function
| String "constant" -> ()
| _ -> ()

Warning 52 [fragile-literal-pattern]: Code should not depend on the actual
  values of this constructor's arguments.
  They are only for information and may change in future versions.
  (see manual section 13.5.3)

val fragile_match_2 : fragile -> unit = 
module Immediate: sig
  type t [@@immediate]
  val x: t ref
end = struct
  type t = A | B
  let x = ref A
end
module Int_or_int64 : sig
  type t [@@immediate64]
  val zero : t
  val one : t
  val add : t -> t -> t
end = struct

  include Sys.Immediate64.Make(Int)(Int64)

  module type S = sig
    val zero : t
    val one : t
    val add : t -> t -> t
  end

  let impl : (module S) =
    match repr with
    | Immediate ->
        (module Int : S)
    | Non_immediate ->
        (module Int64 : S)

  include (val impl : S)
end
« Синтаксис доступа к BigarrayУзлы расширения »
Авторские права © 2026 Institut National de Recherche en Informatique et en Automatique

© 1995-2026 INRIA.
https://ocaml.org/manual/5.5/attributes.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API