8.12 Attributes
(Introduced in OCaml 4.02,
infix notations for constructs other than expressions added in 4.03)
Attributes are “decorations” of the syntax tree which are mostly
ignored by the type-checker but can be used by external tools. An
attribute is made of an identifier and a payload, which can be a
structure, a type expression (prefixed with :), a signature
(prefixed with :) or a pattern (prefixed with ?) optionally
followed by a when clause:
The first form of attributes is attached with a postfix notation on
“algebraic” categories:
This form of attributes can also be inserted after the `tag-name
in polymorphic variant type expressions (tag-spec-first, tag-spec,
tag-spec-full) or after the method-name in method-type.
The same syntactic form is also used to attach attributes to labels and
constructors in type declarations:
Note: when a label declaration is followed by a semi-colon, attributes
can also be put after the semi-colon (in which case they are merged to
those specified before).
The second form of attributes are attached to “blocks” such as type
declarations, class fields, etc:
A third form of attributes appears as stand-alone structure or
signature items in the module or class sub-languages. They are not
attached to any specific node in the syntax tree:
(Note: contrary to what the grammar above describes, item-attributes
cannot be attached to these floating attributes in class-field-spec
and class-field.)
It is also possible to specify attributes using an infix syntax. For instance:
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]
For let, the attributes are applied to each bindings:
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)
8.12.1 Built-in attributes
Some attributes are understood by the type-checker:
-
“ocaml.warning” or “warning”, with a string literal payload.
This can be used as floating attributes in a
signature/structure/object/object type. The string is parsed and has
the same effect as the -w command-line option, in the scope between
the attribute and the end of the current
signature/structure/object/object type. The attribute can also be
attached to any kind of syntactic item which support attributes
(such as an expression, or a type expression)
in which case its scope is limited to that item.
Note that it is not well-defined which scope is used for a specific
warning. This is implementation dependent and can change between versions.
Some warnings are even completely outside the control of “ocaml.warning”
(for instance, warnings 1, 2, 14, 29 and 50).
- “ocaml.warnerror” or “warnerror”, with a string literal payload.
Same as “ocaml.warning”, for the -warn-error command-line option.
- “ocaml.alert” or “alert”: see section 8.21.
- “ocaml.deprecated” or “deprecated”: alias for the
“deprecated” alert, see section 8.21.
- “ocaml.deprecated_mutable” or “deprecated_mutable”.
Can be applied to a mutable record label. If the label is later
used to modify the field (with “expr.l <- expr”), the “deprecated” alert
will be triggered. If the payload of the attribute is a string literal,
the alert message includes this text.
- “ocaml.ppwarning” or “ppwarning”, in any context, with
a string literal payload. The text is reported as warning (22)
by the compiler (currently, the warning location is the location
of the string payload). This is mostly useful for preprocessors which
need to communicate warnings to the user. This could also be used
to mark explicitly some code location for further inspection.
- “ocaml.warn_on_literal_pattern” or “warn_on_literal_pattern” annotate
constructors in type definition. A warning (52) is then emitted when this
constructor is pattern matched with a constant literal as argument. This
attribute denotes constructors whose argument is purely informative and
may change in the future. Therefore, pattern matching on this argument
with a constant literal is unreliable. For instance, all built-in exception
constructors are marked as “warn_on_literal_pattern”.
Note that, due to an implementation limitation, this warning (52) is only
triggered for single argument constructor.
- “ocaml.tailcall” or “tailcall” can be applied to function
application in order to check that the call is tailcall optimized.
If it it not the case, a warning (51) is emitted.
- “ocaml.inline” or “inline” take either “never”, “always”
or nothing as payload on a function or functor definition. If no payload
is provided, the default value is “always”. This payload controls when
applications of the annotated functions should be inlined.
- “ocaml.inlined” or “inlined” can be applied to any function or functor
application to check that the call is inlined by the compiler. If the call
is not inlined, a warning (55) is emitted.
- “ocaml.noalloc”, “ocaml.unboxed”and “ocaml.untagged” or
“noalloc”, “unboxed” and “untagged” can be used on external
definitions to obtain finer control over the C-to-OCaml interface. See
20.11 for more details.
- “ocaml.immediate” or “immediate” applied on an abstract type mark the type as
having a non-pointer implementation (e.g. “int”, “bool”, “char” or
enumerated types). Mutation of these immediate types does not activate the
garbage collector’s write barrier, which can significantly boost performance in
programs relying heavily on mutable state.
- “ocaml.immediate64” or “immediate64” applied on an abstract type mark the
type as having a non-pointer implementation on 64 bit platforms. No assumption
is made on other platforms. In order to produce a type with the
“immediate64“ attribute, one must use “Sys.Immediate64.Make“ functor.
- ocaml.unboxed or unboxed can be used on a type definition if the
type is a single-field record or a concrete type with a single
constructor that has a single argument. It tells the compiler to
optimize the representation of the type by removing the block that
represents the record or the constructor (i.e. a value of this type
is physically equal to its argument). In the case of GADTs, an
additional restriction applies: the argument must not be an
existential variable, represented by an existential type variable,
or an abstract type constructor applied to an existential type
variable.
- ocaml.boxed or boxed can be used on type definitions to mean
the opposite of ocaml.unboxed: keep the unoptimized
representation of the type. When there is no annotation, the
default is currently boxed but it may change in the future.
- ocaml.local or local take either never, always, maybe or
nothing as payload on a function definition. If no payload is
provided, the default is always. The attribute controls an
optimization which consists in compiling a function into a static
continuation. Contrary to inlining, this optimization does not
duplicate the function’s body. This is possible when all
references to the function are full applications, all sharing the
same continuation (for instance, the returned value of several
branches of a pattern matching). never disables the optimization,
always asserts that the optimization applies (otherwise a warning
55 is emitted) and maybe lets the optimization apply when
possible (this is the default behavior when the attribute is not
specified). The optimization is implicitly disabled when using the
bytecode compiler in debug mode (-g), and for functions marked with
an ocaml.inline always or ocaml.unrolled attribute which
supersede ocaml.local.
module X = struct
[@@@warning "+9"]
…
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: 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: 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: 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 9.5)
val fragile_match_1 : fragile -> unit = <fun>
let fragile_match_2 = function
| String "constant" -> ()
| _ -> ()
Warning 52: 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 9.5)
val fragile_match_2 : fragile -> unit = <fun>
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