Caml Light
Xavier Leroy and Damien Doligez's small, portable bytecode implementation of the Caml dialect of ML, begun at INRIA in 1990: the direct ancestor of OCaml, and for over twenty years the language French preparatory-class students learned algorithms in
Created by Xavier Leroy and Damien Doligez (INRIA Rocquencourt, Formel and Para projects)
Caml Light is a small, portable implementation of the Caml dialect of ML, written at INRIA by Xavier Leroy with a memory manager by Damien Doligez. Work began in 1990, and for most of the 1990s it was the principal Caml implementation. It compiled a strict, statically typed functional language with type inference to compact bytecode, and it ran on the Macs and PCs of the day as well as on Unix workstations. That made it practical for classrooms, and for more than twenty years it was the language French classes préparatoires students learned algorithms in. Its design, and much of its code, fed directly into OCaml.
History and Origins
Heavy Caml
INRIA’s Formel project took up ML in the early 1980s. Between 1984 and 1987 Pierre-Louis Curien, Ascánder Suárez and Guy Cousineau built the first complete Caml implementation, which compiled to code for the Categorical Abstract Machine (CAM) and ran on top of Le Lisp. INRIA began distributing Caml V3.1 free of charge in 1987. It became popular, but it was slow and used a lot of memory, and it had no built-in support for separate compilation. It was later nicknamed “Heavy Caml”.
The ZINC experiment (1990)
In February 1990 Xavier Leroy, then at the École Normale Supérieure and INRIA, published INRIA technical report RT-0117, The ZINC experiment: an economical implementation of the ML language. ZINC is a recursive acronym for “ZINC Is Not CAML”. Leroy wanted a system small enough to understand and change, one that could compile modules separately and produce small standalone programs. He noted that the existing CAML system was “70000 lines of very sparsely commented source code”.
ZINC’s main design choices all carried over into Caml Light:
- a bytecode interpreter in portable C, not native code generation;
- a Modula-2-style module system built around separate compilation, not Standard ML’s functors;
- an abstract machine (the ZAM) with a cheap way to apply curried functions to several arguments at once;
- right-to-left evaluation of function arguments.
Caml Light (1990-1991 onward)
According to the OCaml project’s own history, Leroy designed Caml Light “in 1990 and 1991”. Damien Doligez contributed the garbage collector. The 0.5 licence names both authors as researchers in INRIA’s Formel and Para projects. According to the same history, Caml Light was much more efficient than Heavy Caml while staying almost fully backward compatible, and it replaced Heavy Caml.
The changelog marks version 0.3 as the “first public release”. No dated record of 0.3 or 0.4 survives in the public archives. The oldest surviving distribution is 0.5, “of September 1992”, whose tarball on INRIA’s server is dated 10 September 1992. The early releases were distributed by anonymous FTP from ftp.inria.fr.
Design Philosophy
Caml Light chose economy over completeness:
- Small. The README says the runtime is about 100 KB, the compiler another 100 KB of bytecode, and the whole system could be recompiled in 1.5 MB of memory (2 MB in later releases). The authors compared this with the roughly ten times more memory needed by SML/NJ.
- Portable. The only machine-dependent part was a runtime and interpreter written in standard C. The 0.5 README lists testing on fifteen Unix and Mach platforms, from Sun SPARCstations and DECstations to a NeXT Cube, an IBM RS/6000 and a VAX 9215.
- Bootstrapped. The compiler, linker, librarian, toplevel, lexer generator and standard library are written in Caml Light. Apart from a few utilities, only the runtime and the yacc-style parser generator are in C.
- Close to ML, not identical to it. The README calls Caml “quite close to Standard ML, though not strictly conformant”, with “major differences in the module system” that were needed for separate compilation.
Key Features
A taste of the language
| |
Much of this looks like modern OCaml. Two things date it at once: character literals are written with backquotes (`a`), and floating-point arithmetic uses separate operators (+., *.), which the changelog first lists in 0.41 as an “alternate spelling”.
Modules without functors
Every source file is a module. An interface foo.mli declares exported names with value (for example value fact : int -> int;;) and compiles to foo.zi. The implementation foo.ml compiles to foo.zo. A name from another module is written with a double underscore, as in foo__bar or list__map, or brought into scope with the #open "foo";; directive. There are no functors or nested structures. That limitation is what Caml Special Light later removed.
Other features
The manual and changelog document:
- Streams and stream parsers (0.5), for writing lexers and recursive-descent parsers directly in the language
camllexandcamlyacc(0.4), in the style of lex and yacc- Mutable record fields and mutable constructor arguments,
ref,for/whileloops and exceptions, so imperative algorithms can be written directly - A C interface (0.5), which made the Unix system-call and X11 graphics libraries possible
- An incremental major garbage collector (0.5)
- Machine-independent bytecode (0.5): the same executable ran on any architecture
- A type-checked
printf(0.7) and aformatpretty-printing module - A replay debugger (0.7, Unix only), the CamlTk Tcl/Tk binding and a profiler
- Error messages in several languages (0.7): English, French, Spanish, German and Italian
Two commands are provided: camllight, an interactive toplevel, and camlc, a batch compiler “in the spirit of the Unix cc compiler” that produces small standalone programs.
Performance, with context
Leroy’s 1990 ZINC report measured a Knuth-Bendix completion of the group axioms on a Sun 3/280 workstation. The ZINC prototype running as interpreted bytecode took 29.0 s. The distributed CAML 2.6 took 36.6 s, of which 21.2 s was garbage collection. SML/NJ 0.33 took 10.5 s. ZINC compiled to native 68020 code took 9.7 s. These are figures for the ZINC prototype, not for any released Caml Light version.
For release 0.5 the README says only that performance is “five to ten times slower than SML-NJ”. That is the authors’ own estimate, and they give no benchmark for it.
Evolution
| Version | Date | Highlights |
|---|---|---|
| 0.3 | early 1990s (undated) | First public release |
| 0.4 | undated | camllex/camlyacc; ports to the 386 PC (32-bit protected mode) and the Amiga |
| 0.5 | September 1992 | Streams, C interface, incremental GC, camllibr/camlmktop, standalone Macintosh toplevel |
| 0.6 | October 1993 | 64-bit architectures, set/map modules, DPMI-compliant 386 build, examples from Le langage Caml |
| 0.7 | July 1995 | Value restriction, when guards, corrected detection of partial and unused match cases, debugger, CamlTk, format, typed printf |
| 0.71 | February 1996 | Microsoft Windows port (3.1, 95, NT); French Macintosh version |
| 0.72-0.73 | December 1996 - January 1997 | Built-in 'a option type, sprintf, new Emacs mode; Windows fixes |
| 0.74 | December 1997 | Warning for non-unit sequence expressions, more string and float functions |
| 0.75 | 26 January 2002 | Last stable release published by INRIA |
| 0.80-0.82 | 2008-2009 | Relicensed QPL (compiler) / LGPL (library); Mac OS X binaries; 64-bit fixes |
The value restriction in 0.7 was the one deliberate incompatible change. Before 0.7, polymorphic mutable structures could break type safety. From 0.7, a let definition is generalised only when its right-hand side is syntactically a value. The changelog warns that some definitions that used to be polymorphic now fail to type-check. The revised Standard ML of 1997 adopted the same rule, and OCaml uses a relaxed form of it.
Development had already moved on by then. In 1995 Leroy released Caml Special Light, which added an optimising native-code compiler and an ML-style module system with functors. In 1996 Didier Rémy and Jérôme Vouillon’s object system turned it into Objective Caml. After that, Caml Light received only maintenance releases.
Current Relevance
INRIA’s Caml Light page calls the implementation “obsolete, no longer actively maintained” and advises users to switch to OCaml. It says 0.75 “does not work on most modern versions of Windows, Mac OS, and Linux” and is kept “for historical purposes”. The source history is preserved at github.com/camllight/camllight, where the last commit is a graphics-library fix from October 2014.
Its longest use was in French education. Caml Light was the language of the option informatique in the MPSI and MP preparatory classes from the mid-1990s, and François Boisson was still committing fixes to it, including 64-bit memory-allocation fixes, in 2013-2014. On 27 November 2017 a ministry note ended that. According to TI-Planet’s summary of the note (the official text could not be retrieved), the union of preparatory-class science teachers (UPS) had pointed out that Caml Light had gone unmaintained for about ten years, and the note made OCaml the only authorised language. The change applied to first-year MPSI students from the second semester of 2017-18 and to second-year MP students from September 2018.
Why It Matters
- It made ML small and portable. Heavy Caml and SML/NJ needed workstation-class memory. A system that recompiled itself in 2 MB and ran on a PC or Macintosh made typed functional programming practical to teach.
- It is OCaml’s direct ancestor. OCaml keeps its bytecode approach, its C runtime and its compact standalone executables. So do SML implementations such as Moscow ML, which reuses Caml Light’s runtime.
- It trained a generation. For more than twenty years, French students in the scientific preparatory classes learned recursion, pattern matching and algorithms in Caml Light.
- It showed that interpretation can be good enough. The ZINC report’s argument, that a well-designed bytecode interpreter could come close to naive native code while staying tiny and portable, was borne out in practice, and OCaml’s bytecode compiler still follows that approach.
Timeline
Notable Uses & Legacy
French preparatory classes (CPGE)
The language of the MPSI and MP option informatique from the mid-1990s until the 2017-18 school year, when a ministry note replaced it with OCaml; practicals from 1995-96 at the Lycee du Parc in Lyon used Caml Light 0.71
Moscow ML
Sergei Romanenko and Peter Sestoft's Standard ML implementation reuses, according to its README, "the entire runtime system and many other ideas from the Caml Light implementation"
Le langage Caml (Weis and Leroy)
A French programming textbook by the language's authors, first published by InterEditions in 1993 according to bookseller listings, whose example programs shipped in the Caml Light distribution from 0.6
The Functional Approach to Programming (Cousineau and Mauny)
A Cambridge University Press textbook (1998) whose programs were written in Caml Light