Chapter 8  Language extensions

This chapter describes language extensions and convenience features that are implemented in OCaml, but not described in the OCaml reference manual.

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:

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

The first form of attributes is attached with a postfix notation on “algebraic” categories:

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  
 

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:

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

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:

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  
 
definition::= let [reclet-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  
 

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:

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

(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)

12.1  Built-in attributes

Some attributes are understood by the type-checker:

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: 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