- No warning about leading zeroes*1
- No warning about uncalled unit functions in a sequence*1
- OCaml has tagged integers, 1 bit shorter than you expect*1
modis truncating (like in C) instead of Euclidean (like in Perl, Python)- C-resembling equality ops
== !=are physical, not structural - Evaluation order of arguments to constructors, as to functions in many languages, is undefined
- The second of
[%defer ...]; [%defer ...]is an uninterpreted extension 'defer'.
Caveats elsewhere:
- OCaml: the bugs so far (source of "*1" items)
- 7 OCaml Gotchas
No warning about leading zeroes
(* o23.ml *)
let () =
(* set my perms to u=rwx, g/o nothing *)
Unix.chmod Sys.argv.(0) 0700
$ ocamlfind ocamlc -linkpkg -package unix o23.ml $ ls -ld a.out|cut -d' ' -f1 -rwxr-xr-x. $ ./a.out $ ls -ld a.out|cut -d' ' -f1 --w-rwxr-T.
0700 is decimal 700, not the octal number mapping to binary 111_000_000. Octal 700 is written 0o700.
# let huh = 0700 in huh=700, huh, 0o700, 0b111000000;;
- : bool * int * int * int = (true, 700, 448, 448)
No warning about uncalled unit functions in a sequence
(* o24.ml *)
let trace fn =
print_endline "START";
fn ();
print_endline "END"
let () = trace (fun () -> Printf.printf "Hello %s!\n")
$ ocaml o24.ml
START
END
$ ocaml -strict-sequence o24.ml
File "./o24.ml", line 6, characters 26-53:
6 | let () = trace (fun () -> Printf.printf "Hello %s!\n")
^^^^^^^^^^^^^^^^^^^^^^^^^^^
Error: This expression has type string -> unit
but an expression was expected of type unit
Hint: This function application is partial, maybe some arguments are missing.
That printf, by the %s, is expecting another argument. Merlin helpfully typed the function in the last line as unit -> string -> unit when I couldn't immediately see the problem.
OCaml has tagged integers, 1 bit shorter than you expect
Like typical Common Lisp implementations, and also to give the GC a fast way to distinguish pointers from other data, OCaml int has one less bit available to the programmer than the machine integer has. So on a 64-bit machine,
# max_int, Int64.(div max_int 2L |> to_int) = max_int;;
- : int * bool = (4611686018427387903, true)
mod is truncating (like in C) instead of Euclidean (like in Perl, Python)
$ perl -le 'print -13%100' 87 $ ocaml -e 'Printf.printf "%d\n" ((-13) mod 100)' -13
Euclidean definition from discuss.ocaml.org:
let (%) x y =
let z = x mod y in
if z < 0 then z + y else z
C-resembling equality ops == != are physical, not structural
# let a = "hello" let b = a ^ "";; val a : string = "hello" val b : string = "hello" # a = b;; - : bool = true # a == b;; - : bool = false # a <> b;; - : bool = false # a != b;; - : bool = true
Evaluation order of arguments to constructors, as to functions in many languages, is undefined
Despite being very familiar with this error from C, I was slow to recognize it in this code:
# let rec lines () = try read_line () :: lines () with End_of_file -> [];;
val lines : unit -> string list = <fun>
# lines ();;
Stack overflow during evaluation (looping recursion?).
It's not defined which argument to :: is evaluated first, and on my machine the tail argument was evaluated first, similarly to
let rec lines () =
let tl = lines () in
try read_line () :: tl with End_of_file -> []
Also true of let ... and
The second of [%defer ...]; [%defer ...] is an uninterpreted extension 'defer'.
(* this works: *)
[%defer Unix.close client];
();
[%defer Unix.shutdown client Unix.SHUTDOWN_ALL];
(* and this doesn't! *)
[%defer Unix.close client];
[%defer Unix.shutdown client Unix.SHUTDOWN_ALL];
(* ^^^^^
Error: Uninterpreted extension 'defer'.*)
This is an unfortunate limitation of ppx, or perhaps just of ppx_defer: it needs a normal following expression to latch onto, and the second 'defer' doesn't cut it.