A curious file in the original MetaOCaml CVS repository lists several short notes from the meeting in Paris on September 29, 2000 between Xavier Leroy and Walid Taha. One note stands out: ``we (Xavier!) were able to compile and run "run bracket 1"!!'' One may take this moment as the birth of MetaOCaml.

MetaOCaml started as a fork of OCaml along the lines of MetaML. Designed and architectured by Walid Taha and developed by Cristiano Calcagno, MetaOCaml had reached its current form by 2003. The environment classifiers appeared at the end of that year. Native code compilation and offshoring (translating the generated code into C and Fortran) were added in 2004.

As MetaOCaml was being developed, new versions of the mainline OCaml were released with sometimes many fixes and improvements. The MetaOCaml team tracked new OCaml releases and merged the changes into MetaOCaml. (The MetaOCaml version number has as its base OCaml's release version.) The merge was not painless. For example, any new function in the OCaml compiler that dealt with Parsetree (AST) or Typedtree has to be modified to handle MetaOCaml extensions to these data structures. The merge process became more and more painful as the two languages diverged. For instance, native code compilation that first appeared in MetaOCaml 3.07 relied on SCaml, a large set of patches to OCaml by malc at pulsesoft.com to support dynamic linking. OCaml 3.08 brought many changes that were incompatible with SCaml. Therefore, in MetaOCaml 3.08 the native compilation mode was broken. The mode was brought back in the Summer 2005, by re-engineering the SCaml patch and implementing the needed parts of dynamic linking without any modification to the OCaml code. The revived native compilation has survived through the end.

In 2006, MetaOCaml became the basis for Concoqtion. The increasing divergence between OCaml and MetaOCaml made it harder and harder to merge the changes. With the funds for the project dried up and the daunting prospect of merging many changes that appeared in OCaml 3.10 and 3.11, the development of MetaOCaml has ceased. Its last released version was 3.09.1 alpha 030.

Although the original development team could no longer support MetaOCaml, the users of the language, Jacques Carette in particular, could not bear it fall by the wayside. At the Jacques Carette's urging, the merge of OCaml 3.11 changes was undertaken in February 2010. The lack of funding and limited resources made it imperative to keep close to the mainline OCaml and avoid the divergence at all cost. Everything not directly related to staging was removed, including tag elimination and Concoqtion. 23 fewer files in the OCaml distribution were affected by MetaOCaml. Walid Taha suggested to name the new, bare-minimum line of MetaOCaml as BER MetaOCaml. Its first version N002 was released on March 1, 2010.

BER MetaOCaml established the separation of the kernel from the user-level. Like with an OS kernel, changes to the MetaOCaml kernel require `rebooting' (recompiling the MetaOCaml) and may render the system unusable. User-level changes affect only particular programs and are easier to develop. The MetaOCaml kernel is responsible for producing and type-checking code values. User-level deals with processing, or `running' code values: pretty-printing, executing, compiling to byte-code, to native code, to C, etc. Programmers may write new ways of processing code values -- for example, to compile them to LLVM or JavaScript -- without modifying OCaml or BER MetaOCaml. In the BER N002 distribution, the kernel included the 59KB patch to OCaml distribution and the 54KB-long typing/trx.ml ; user-level consisted of a pretty-printer (59KB source code) and the support for byte-code execution of the generated code and the custom top level (3KB, all in all). There was also 20KB of test code.

The 59KB patch to OCaml seems large. Part of it is necessary. Since BER MetaOCaml extends the AST data type, Parsetree , with variants Pexp_bracket , Pexp_escape , Pexp_run , Pexp_cspval for the staging constructs, any part of OCaml that processes the AST has to be modified. Quite many parts of a compiler deal with AST. In a multi-stage language, each expression is associated with a stage level, present-stage or one of the progressively future stages. The original MetaOCaml stored the level in an extra field val_level of the value_description record that maintained type and other information for each identifier. Since the map from identifiers to value_description is the typing environment, it is used all throughout the type checker. Therefore, the addition of a new field required great many changes. A new OCaml version modifies the type checker quite heavily. Integrating all these modifications into MetaOCaml, accounting for the new field val_level , is a hard job. It is avoidable however: we may associate identifiers with levels differently, by adding a new map to the environment that tells the level of each future-stage identifier. Any identifier not in the domain of that map is assumed present-stage. The value_description record then remains intact. BER MetaOCaml N100 (see below) takes this route. The original MetaOCaml modified the AST further, to store the information about data constructors used in the generated code (actually, the AST that corresponded to the generated code contained the entire present-stage environment of the type-checker.) Great many patches to OCaml came that way. BER N100 imposed the constructor restriction as described elsewhere on this page, eliminating the extra AST modifications and the need to patch OCaml further. Thus, if one takes as the goal bringing MetaOCaml closer to OCaml, the amount of modifications to OCaml can indeed be minimized -- as BER N100 has shown.

OCaml release 3.12 brought unexpectedly many new features to the language, for example, first-class modules. OCaml 4.0 added GADTs and dynamic linking. Integrating that many changes into BER MetaOCaml N002 was too depressing to contemplate. BER MetaOCaml N100, developed in January 2013 and released on January 31, is a clean-state re-implementation of MetaOCaml. Rather than merging OCaml 4.0 into the MetaOCaml branch, BER N100 started anew. It took the OCaml distribution, extended its AST with the staging constructs, and kept adding code until the constructs were fully handled -- until there were no inexhaustive pattern-matching throughout the OCaml code. The exhaustiveness check was very helpful. Great care was taken to modify as fewer OCaml data structures as possible. Here is the break-out of the BER N100 distribution: the kernel consists of the 49KB patch to OCaml files (modifying 28 OCaml files, 6 of which trivially) and the 77KB-long completely re-written typing/trx.ml with very many comments. User-level includes the 58KB pretty-printer (heavily modified by Jacques Carette), and a number of small files to support top-level and run , 3KB all in all. There are 54KB of tests, including, for the first time, a regression test suite. BER N100 is much less invasive into OCaml: compare the size of the patch to the main OCaml type-checker typing/typecore.ml , which contains the bulk of the changes for type checking the staging constructs. In the previous version BER N004, the patch had 564 lines of additions, deletions and context; now, only 328 lines.

BER MetaOCaml N101, released in November 2013, cleaned-up MetaOCaml further. The positive experience with the scope extrusion check has made it possible to remove environment classifiers, and hence notably simplify the type checking of staging constructs. The operation to run the code no longer required dedicated type checking rules. In BER N101, it became an ordinary function, moved out of the MetaOCaml kernel. Internally, BER N101 improved the scope extrusion check and optimized the translation of staging constructs, especially binding forms. Pretty-printing of the code has become part of OCaml and hence no longer has to be maintained separately.

The version N102 released on January 1, 2015 was another significant re-write, although with hardly any user-visible changes. The BER N102 code makes the extensive use of attributes, the new feature of OCaml 4.02. Staging annotations -- brackets, escapes and CSP -- are now really annotations: attributes on the Parsetree and Typedtree. A specifically Typedtree attribute marks non-expansive nodes (the non-expansiveness check is performed before the bracket-translation but is used only after). An attribute on value_description tells the staging level of the value. There is no longer a separate Typedtree traversal pass, after the type checking, to translate brackets and escapes. That means that for staging-annotation-free code, MetaOCaml has no substantial overhead. BER N102 has started on revamping cross-stage-persistence; quite a few CSP have become printable and, mainly, serializable. Non-serializable CSP were the only impediment to native MetaOCaml. The number of files in the OCaml distribution that are patched by MetaOCaml fell down from 32 to mere 7. The patch size is reduced to 34KB. It is now a distinct possibility that MetaOCaml becomes just a regular library or a plug-in, rather being a fork.

The version N104 (January 1, 2017) brings back native MetaOCaml and implements two novel features, not seen in MetaOCaml or MetaML before: first-class pattern-matching and let-insertion as a primitive.

The version N107 (October 5, 2018) brings back offshoring, in a different way, and adds explicit lifting. The code type is no longer special and pre-defined (which means only 4 OCaml files are modified by MetaOCaml: lexer, parser, pretty-printer, and typecore.ml).

Developing and especially maintaining a new language is gigantic work. Engineering a new language as a dialect of a well-maintained one is hard but pays in many ways.