RTT: Run-time types for OCaml

RTT is a prototype implementation of run-time typing in OCaml. It allows programmers to use functions such as to_string: α → string (for all α). The present solution focuses on being fully automatic, and providing the actual run-time type of values (including when it is more precise than the static type, because of polymorphism). On the other side, types are represented in an untyped way (no GADTs) and we only provide a minimal library for the purpose of the demonstration.

You can try RTT online ! (takes a few seconds to load)

1  Overview

RTT is implemented as a pre-processor which is inserted in the compilation command with the usual -pp option. Programs compiled with run-time types may use the RTT API to benefit from the added functionality.

Hello world example

Here is a minimal example using RTT on a list of string:

Rtt.to_string ["Hello""world"];;

Evaluating this in Try RTT will give the result:

- : string = "[\"Hello\"; \"world\"]"

which is the string representing the initial value.

A more complex example

Here is an example program which parses an OCaml source file and displays its syntax tree:

let pprint_ast parse file =
  let c = open_in file in
  let ast = parse (Lexing.from_channel c) in
  close_in c;
  Format.printf "%t\n%!" (Rtt.pprint ast)

let _ =
  Arg.parse
    []
    (function file ->
      if Filename.check_suffix file ".ml" then pprint_ast Parse.implementation file
      else if Filename.check_suffix file ".mli" then pprint_ast Parse.interface file
      else prerr_endline (file ^ " is not an OCaml source file"))
    (Sys.argv.(0) ^ " <file.ml[i]>")

The output of applying it to itself looks like:

[
  {
    pstr_desc = 
      Pstr_value (
        Nonrecursive,
        ...

This example illustrates two things. First, Rtt.pprint really uses the dynamic type of ast (which can be either Parsetree.structure or Parsetree.signature). Second, a run-time representation is available even for types defined in external, normally compiled libraries, as long as they are not abstract.

2  Installing RTT

Installation is not difficult, but requires the OCaml sources (version 4.00.1 only), as well as an installed version of OCaml 4.00.1. Here are the steps to install:

After installing RTT  you may run make test/test_rtt and make test/test_nortt to check the installation and see a minimal example.

The source code repository can be found on the RTT project page on the OCaml Forge.

3  Compilation

The compilation and linking commands should look like the following:

      ocamlc -pp "rtt <includes>" -I +rtt -I rtt_stubs <includes> -c <file.ml>

      ocamlc <includes> -I +rtt rtt.cma <stubs> <files.cmo>

In the above commands, <includes> is the set of include (-I) options, which must be passed to RTT (since it is a transformation of typed programs), and <stubs> is the list of stubs generated by RTT for the external libraries used by the program (other than the standard library). The quickest solution is to replace <stubs> with:

      -I rtt_stubs `tail -n+2 rtt_stubs/stubs.mllib | awk '{print "rtt_stubs/"$0".ml"}'`

which will insert all .ml stub files so that they are compiled and linked at the same time. A more scalable option is to compile separately all .ml files in the sub-directory rtt_stubs created by RTT (.mli files are compiled automatically), then create a library stubs.cma according the order specified by the file rtt_stubs/stubs.mllib, and use this library in place of <stubs>.

Using RTT with a pre-processor

Currently, combining RTT transformation with other (syntactic) pre-processing (typically camlp4) should be done by passing the pre-processing command to rtt itself, as follows:

      ocamlc -pp "rtt -pp \"camlp4 <options>\"" -I +rtt <file.ml>

4  Using RTT in OCaml sources

The RTT API consists of the two following modules:

Another module Rtt merges the three above modules for convenience.

RTT-compiled OCaml standard library

Calling RTT with option -rtt-stdlib, and linking the resulting program with the file rtt_stdlib.cma (in addition to rtt.cma) will replace the OCaml standard library by an RTT-compiled version, which will provide maximum accuracy. Unfortunately, the types in the RTT standard library are not compatible with the original standard library, so in practice this feature can only be used if all the libraries used by a program have been compiled with rtt -rtt-stdlib.

Other options

The options -nostdlib and -nopervasives of rtt should be used consistently with the enclosing compilation command. The option -text causes RTT to output a pretty-printed source file instead of an OCaml AST. This is mainly useful for debugging.

Other modules used internally

Some other modules are visible but not meant to be used directly:

5  Disabling RTT

An RTT-using program may be compiled without instrumentation, with the following commands (which use a stub implementation of the RTT functions):

      ocamlc -I +nortt <includes> -c <file.ml>

      ocamlc <includes> -I +nortt rtt.cma <files.cmo>

6  RTT toplevel

A customized toplevel is provided: rttocaml, which already contains the RTT library and the RTT-compiled OCaml standard library. To use it, just launch rttocaml and start using functions from module Rtt. The resulting types printed when evaluating a phrase are those of the transformed program, which may help to understand the transformation.

7  Limitations

RTT handles a comprehensive subset of OCaml which allows for real experiments, but it is still an ongoing work.

Currently, the most annoying limitation concerns the preservation of type and module equalities when constraining a module to a signature, if this module is (or contains) a functor. The problems comes from the fact that when casting a module to a module type refines the type of some values, these need to be redefined by the RTT transformation because their added rttype parameters change (both their number and their use in the function’s body). Applying a functor to a module is an implicit case of casting, and this implies that the types contained in the application result no longer have the path F(M).t, but something like F(wrap M).t, which are not considered equal by OCaml’s notion of applicative functors. The same problem occurs when casting the functor itself to a functor type the arguement of which contains values with a more general type. In all these cases, the transformed program may not type-check if typing the original program relies on functors being applicative.

Other than that, the following language features are not supported:

Besides, some other features have not been seriously tested.


This document was translated from LATEX by HEVEA.