I’m trying to understand the performance cost of exceptions. Here is a function reading lines from stdin and returning a list in reverse order:
(*using options*)
let input_rev () =
let rec aux acc =
match In_channel.input_line stdin with
| None -> acc
| Some s -> aux (s :: acc)
in aux []
(*using exceptions*)
let input_rev' () =
let rec aux acc =
try aux @@ read_line () :: acc
with End_of_file -> acc
in aux []
Is input_rev'slower than input_rev? I feel like the recursive nesting of ‘try..with’ blocks smells a little bit, but maybe it’s fine. (I’m talking about performance only, not the overall merits of using options.)
If it is slower, is there a way to rewrite input_rev'without nesting ‘try…with’ blocks and without using mutation?
Last question: is my version of input_rev'tail-recursive? Or does the ‘try’ before the function call break tail-recursion?
I agree with @SkySkimmer that you should make input_rev' tail recursive, and use Stdlib.input_line stdin instead of read_line () to avoid the extra “flush” performed by read_line.
Once you’ve done that, I think input_rev and input_rev' should be about as fast. Try doing some timings if you’d like to be sure.
Here is a version of input_rev that installs a single exception handler instead of one handler per line:
let input_rev () =
let res = ref [] in
begin try
while true do
res := input_line stdin :: !res
done
with End_of_file ->
()
end;
!res
Exception handling is cheap in OCaml, and I/O is always expensive, so I wouldn’t expect this code to make much of a speed difference.