WHAT IS OCAML1TO2:

ocaml1to2 is a tool to help converting Objective Caml source from
version 1.07 to version 2.00, in particular to adapt to the new syntax
of classes.

Most of the time, the output of ocaml1to2 can be compiled straight
away with Objective Caml 2.00.  There are a few cases that require
manual inspection and intervention (see below).

The translator tries hard to preserve the indentation and comments of
the original source.  The only situation where comments can be lost is
if they occur "in the middle" of a class construct being rewritten.
For instance:

        class (* comment 1 *) c () =
          (* comment 2 *)
          val x = 0
          (* comment 3 *)
        end

The comments 2 and 3 will be preserved, but 1 will be lost.

OCaml1to2 is intended to help manual conversion of sources, not as a
100% automatic conversion tool.  If you have problems with the output
of the translator, you're welcome to report them to <caml-light@inria.fr>,
but we don't guarantee an immediate fix; it might be faster to fix the
translated code by hand instead.


BUILDING IT:

You need Objective Caml 2.00 installed.  To compile, just type:

        make                    # under Unix
        nmake -f Makefile.nt    # under Windows

This creates an executable "ocaml1to2" in the current directory.
Copy it anywhere in your executable search path.

USING IT:

Usage:

   ocaml1to2 [-print] [-replace] <source1> <source2> <...>

   The <source> arguments are either .ml or .mli source files.

Typical uses are:

    ocaml1to2 source.ml

        Convert source.ml, storing the result of conversion in source.ml.new
        You can then look at source.ml.new and if you're happy,
        replace source.ml with it.

    ocaml1to2 -replace source.ml

        Convert source.ml, storing the result of conversion in the same
        file source.ml.  The old source is saved in source.ml.old.

    ocaml1to2 -replace `find . \( -name '*.ml' -o -name '*.mli' \) -a -print`

        Quick massive in-place conversion of all your sources in the
        current directory and its sub-directories.  Use with caution...

    ocaml1to2 -print source.ml

        Convert source.ml and send result to standard output


WARNINGS:

ocaml1to2 will emit warnings when manual inspection and intervention
is required.  This includes the following cases:

1- Use of "object" or "initializer" as an identifier:

These are reserved keywords in OCaml 2.00.  Please rename them
manually.

2- "val private" declarations:

In OCaml 2.00, there is no longer a "private" modifier on class instance
variables.  Privacy is ensured by class type constraints, e.g. by
putting a class type that does not mention the variable in the .mli
interface or in a signature constraint.

If your original source has an explicit interface or signature
constraint, as in

        foo.ml                          foo.mli

        class c () =                    class c (unit) =
          val private x = 0               (* no x *)
          ...                             ...
        end                             end

then the translator will simply remove the "private" modifier and
everything is correct:

        foo.ml                          foo.mli

        class c () =                    class c : unit ->
          object                          object
            val x = 0                       (* no x *)
            ...                             ...
          end                             end

If your original source did not have an explicit interface or signature
constraint, the translated code will compile all right, but the
instance variable will no longer be private.  You may add a class type
constraint to remedy this.

3- Making "mutable" an inherited instance variable:

OCaml 1.07 supports the following idiom (of dubious programming value):

        inherit c ()    (* c defines a non-mutable instance variable x *)
        val mutable x   (* without initialization *)
        ...

This is no longer possible in OCaml 2.00.  You must make "x" mutable
in the superclass c, or use a different field name in the subclass.

4- "closed" classes are no longer supported:

In rare circumstances, an OCaml 1.07 class had to be flagged "closed".
This corresponds to cases where the type of "self" becomes non-extensible
through unification, and therefore subclasses cannot define additional
methods.  In OCaml 2.00, such classes are rejected during typing.  You
must rewrite the class so that the "self" type remains extensible.  It
usually suffices to introduce coercions (self :> c) from the self type
to a known closed class type c.

5- `val v = v' no longer needed, commenting it out

This is explained in more details in the section "ERRORS" below.
Briefly, in OCaml 2.00, methods are allowed to refer to initialization
parameters, so it is no longer necessary to bind initialization
parameters to instance variables, as in 1.07.  The translator assumes
that all instance variables declaration of the form "val v = v"
were introduced only for giving the methods access to the
initialization parameter v, and so it comments them out.  This is
often correct, but not always: subclasses may need the instance
variable v.  In this case, you'll have to de-comment out the
"val v = v" declaration in the translated file.


ERRORS DURING COMPILATION OF TRANSLATED SOURCES:

There are some semantic differences between OCaml 1.07 and OCaml 2.00
that the translator does not handle.  Those must be fixed by hand.
The most common problem is:

``The instance variable <varname>
  cannot be accessed from the definition of another instance variable''

This is typically caused by classes of the following form:

        class myclass v =
          object
            val v = v
            val w = sin v
            ...
          end

In 1.07, "val w = sin v" was understood as "apply sin to the
initialization parameter v".  In 2.00, it is understood as
"apply sin to the instance variable v", and this is not
permitted in the initializing expression for an instance variable.

Solution 1: name the initialization parameter and the instance
variable differently:

        class myclass v_init =
          object
            val v = v_init
            val w = sin v_init
            ...
          end

Solution 2: in many cases, you can now dispense with the "val v = v"
entirely, since methods are now allowed to refer to initialization
parameters of their class.  (In 1.07, methods could not refer to
initialization parameters, forcing the use of dummy instance variables to
record the values of the initialization parameters.)

Indeed, the translator removes by itself variable declarations of the
form "val v = v" (after emitting a warning).  However, some manual
intervention is needed for more complex situations, e.g.
"val mutable v = v".
