31

I saw the following function call in Yacfe example:

  Visitor_c.vk_program { Visitor_c.default_visitor_c with
    Visitor_c.kexpr = (fun (k, bigf) exp -> 
      match Ast_c.unwrap_expr exp with
      | Binary(e1, Logical (Eq), (((Constant(Int("0")) as _e2),_t),ii)) -> 

          (match Ast_c.get_onlytype_expr e1 with 
          | Some (qu, (Pointer _,_ii)) -> 

              let idzero = Common.tuple_of_list1 ii in
              idzero.cocci_tag := 
                Ast_cocci.MINUS (Ast_cocci.NoPos, [[null_addon]]), [];

          | _ -> k exp
          )
      | _ -> k exp
    );
  } ast;

I can see a function call with record initialized as the first argument, and ast as the second argument.

What I'm not familiar with is the syntax of the form:

{Visitor_c.default_visitor_c with Visitor_c.kexpr = some_value;}

What does this means? I know a record can be initialized like {name=value;name=value;...}, but I'm not familiar with the {X with name=value}, can you tell me what it means?

I can't find in the Ocaml Manual nothing about legal record value initialization other than the following:

6.2.3 Records

Record values are labeled tuples of values. The record value written { field1 = v1; …; fieldn = vn } associates the value vi to the record field fieldi, for i = 1 … n. The current implementation supports records with up to 222 − 1 fields (4194303 fields).

I'll be glad if in your answer you'll include a reference to the relevant section in the OCaml manual.

GEOCHET
  • 21,119
  • 15
  • 74
  • 98
Elazar Leibovich
  • 32,750
  • 33
  • 122
  • 169

2 Answers2

48

This is sometimes called a "record update" or "functional update" or something like that. It evaluates to a new record of the same type as X, and whose fields are initialized to the same as those in X, except the ones which are listed after the "with", which are initialized to those given values.

It is useful for immutable records, as a convenient way to take such a record and change one or two things on it (which in an imperative language you would typically mutate the fields), without having to list out all the fields that are not changed.

It is described in the OCaml manual section 6.7.3, scroll down to "Records", second paragraph.

For those who are familiar with Haskell, the OCaml syntax

{ expr with field1 = expr1 ; ... ;  fieldn = exprn }

is the same as the Haskell syntax

expr { field1 = expr1 , ... ,  fieldn = exprn }
newacct
  • 119,665
  • 29
  • 163
  • 224
  • Thanks. How could I google that? It's pretty deep into the manual, and I couldn't find it easily. – Elazar Leibovich May 31 '09 at 08:28
  • 4
    I don't know how you would google it. I just happened to know this one. But at the top of that page (section 6.7) lists the grammar of all the expressions that are valid in OCaml, so if you want to understand an expression you can start there first, and if you see it scroll down to the appropriate part that describes it. And in general, Chapter 6 deals with various aspects of the grammar of the OCaml language; there are sections dealing with type expressions, patterns, classes, modules, etc. So if you need to look up anything I would start at the appropriate section there first. – newacct May 31 '09 at 17:13
  • Wow, I didn't know you could keep listing `fieldn = expern;`. Thanks! – Nick Heiner May 02 '12 at 16:28
15

To correct the previous reply, the new record is not always of the same type as the old record. For example, you can have something like that:

type 'a t = {
  id : int;
  value : 'a;
}
let old_t = { id = 3; value = "foo" }
let new_t = { old_t with value = 3 }

As a result, old_t is of type string t, while new_t is of type int t.

Fabrice Le Fessant
  • 4,222
  • 23
  • 36