Skip to content
Part IA Michaelmas Term

Types and Type Inference

int vs float

OCaml distinguishes strictly between integer and floating-point types:

TypeConstantsOperators
int0, 1, 42+, -, *, /, mod
float0.0, 1.0, 3.14+., -., *., /.

The decimal point makes all the difference: 0 is an int; 0.0 is a float. OCaml will never automatically convert between them — this prevents subtle rounding errors.

Type constraints (annotations)

Although OCaml normally infers types, you can supply hints for debugging or to force a more specific type:

let square (x : float) = x *. x
(* val square : float -> float = <fun> *)

This constrains x to be float. Alternatively, constrain the result type:

let square x : float = x *. x
(* val square : float -> float = <fun> *)

Type constraints can appear almost anywhere in an expression.

Type inference

OCaml is unusual in that it infers types automatically. You rarely need to specify types explicitly. The compiler works out the most general type that an expression can have. For example, from x *. x it deduces x must be float because *. requires float operands.

Conversion functions

To mix integers and floats, explicit conversion is required:

int_of_float 3.14159   (* - : int = 3 *)
float_of_int 3         (* - : float = 3. *)

These conversion functions truncate (not round) when going from float to int.

Modules and compound identifiers

OCaml’s libraries are organised using modules. Functions from modules are accessed with compound identifiers using dot notation:

Float.of_int 3    (* equivalent to float_of_int *)
String.length "abc"
List.rev [1; 2; 3]

The module name acts as a namespace, preventing name clashes between different libraries. Thousands of library functions are available for text processing, operating system interaction, and numerical computation.

Why typed languages?

Some languages have just one numeric type, converting automatically between formats. This is:

  • Slower, because of runtime conversions
  • Potentially inaccurate, due to unexpected rounding

OCaml’s type system catches mismatches at compile time, guaranteeing that no type errors occur at runtime. Inside the computer all data are bits; the compiler uses types to generate correct machine code, and types are not stored during program execution.