Migael123
Migael123

Reputation: 1

OCaml: Upon encountering an exception, the for cycle should just ignore it and continue without tossing me out

So i have this code:

let matrix = [|
  [| true; true; true |];
  [| false; false; false |];
  [| false; true; true |];
  [| true; false; false |]
|];;

for i = 0 to 10 do
  for j = 0 to 10 do
    try 
      if matrix.(i).(j) = true then 
        print_string "works"
    with
    | Invalid_argument "Index out of bounds" -> ();
  done;
done;

I want the exception handler to just continue the loop without printing works, instead it tosses me out and still gives me an exception. What am i doing wrong here?

Upvotes: 0

Views: 133

Answers (3)

octachron
octachron

Reputation: 18902

In general, Invalid_argument _ exceptions should not be catch nor matched. Those exceptions are meant as programming errors that should be avoided before they happen. In this specific case, this means checking that the indices are within the bound of the matrix before using them.

For instance:

for i = 0 to 10 do
  for j = 0 to 10 do
    if i < Array.length matrix && i >= 0
    && j < Array.length matrix.(i) && j >= 0
    && a.(i).(j)
    then print_string "works"
  done
done

It is also possible to define a matrix access operator that returns an option type in order to factorize the bound checking outside of the loop:

let (.?()) a (i,j) =
  if i < Array.length a && i >= 0
  && j < Array.length a.(i) && j >=0
  then
    Some (Array.unsafe_get (Array.unsafe_get a i) j)
  else None

for i = 0 to 10 do
  for j = 0 to 10 do
    match matrix.?(i,j) with
    | None | Some false -> ()
    | Some true -> print_string "work"
  done
done

Upvotes: 1

Chris
Chris

Reputation: 36611

Goswin is correct about the case mismatch in matching the exception. You also have unnecessary semicolons in your code as you are not chaining multiple expressions together.

for i = 0 to 10 do
  for j = 0 to 10 do
    try 
      if matrix.(i).(j) = true then 
        print_string "works"
    with
    | Invalid_argument _ -> ()
  done
done

Also note that in OCaml 4.02 and later, we can handle exceptions directly in a match, so this code could be expressed as:

for i = 0 to 10 do
  for j = 0 to 10 do
    match matrix.(i).(j) with 
    | true -> print_string "works"
    | false | exception Invalid_argument _ -> ()
  done
done

If you wish to avoid the exception handling altogether, you could quite simply bounds check.

let height = Array.length matrix in
for i = 0 to (min 10 (height - 1)) do
  let width = Array.length matrix.(i) in
  for j = 0 to (min 10 (width - 1)) do
    if matrix.(i).(j) then 
      print_string "works" 
  done
done

Upvotes: 1

Goswin von Brederlow
Goswin von Brederlow

Reputation: 12342

When I compile this I get:

Warning 52: Code should not depend on the actual values of
this constructor's arguments. They are only for information
and may change in future versions. (See manual section 9.5)

Well, you ignored this, so when I run it I get:

worksworksworksException: Invalid_argument "index out of bounds".

"Index out of bounds" is not the same as "index out of bounds". You are catching the wrong exceptions.

Upvotes: 2

Related Questions