I have a large sum type originating in existing code. Let's say it looks like this:
type some_type =
| Variant1 of int
| Variant2 of int * string
Although both Variant1
and Variant2
are used elsewhere, I have a specific function that only operates on Variant2
:
let print_the_string x =
match x with
| Variant2(a,s) -> print_string s; ()
| _ -> raise (Failure "this will never happen"); ()
Since this helper function is only called from one other place, it is easy to show that it will always be called with an input of Variant2
, never with an input of Variant1
.
Let's say the call looks like this:
let () =
print_the_string (Variant2(1, "hello\n"))
If Variant1
and Variant2
were separate types, I would expect OCaml to infer the type Variant2 -> ()
for print_the_string
, however, since they are both variants of the same sum type, OCaml infers the signature some_type -> ()
.
When I encounter a program that throws an exception with a message like "this will never happen," I usually assume the original programmer did something wrong.
The current solution works, but it means that a mistake in the program would be caught at runtime, not as a compiler error as would be preferable.
Ideally, I'd like to be able to annotate the function like this:
let print_the_string (x : some_type.Variant2) =
But, of course, that's not allowed.
Question: Is there a way to cause a compiler error in any case where Variant1
was passed to print_the_string
?
A related question was asked here, but nlucarioni and Thomas's answers simply address cleaner ways to handle incorrect calls. My goal is to have the program fail more obviously, not less.
Update: I'm accepting gallais's solution as, after playing with it, it seems like the cleanest way to implement something like this. Unfortunately, without a very messy wrapper, I don't believe any of the solutions work in the case where I cannot modify the original definition of some_type
.