F# Conditional Expressions if…then..else returning unit or ()
F# Conditional Expressions if…then..else returning unit or ()
F#'s Condtional Expressions require a condition to check, a branch for true, and a branch for false. For example:
let x =
if ("hello" = null)
then true
else false //error if else branch missing
However, something gets weird when unit, aka (), is involved.
unit
()
let y =
if ("hello" = null)
then raise <| new ArgumentNullException()
else () //happy with or without else branch
And more simply:
let z =
if ("hello" = null)
then ()
else () //happy with or without else branch
Why isn't anelse branch required when unit is returned?
else
unit
2 Answers
2
The types of the values produced in each branch must match. If there is no explicit else branch, its type is unit. Therefore, if the type of the then branch is any type other than unit, there must be an else branch with the same return type.
If you remove else from the first snippet, it's equivalent to
else
let x =
if ("hello" = null)
then true
else ()
which doesn't typecheck.
Why? I'd guess for compatibility with OCaml.
The else expr3 part can be omitted, in which case it defaults to else (). (7.7.2)
else expr3
else ()
You can think of unit-returning if as an equivalent to the C-like if statement as opposed to the expression.
unit
if
if
In the sense that "if OCaml didn't allow omitting
else (like SML doesn't), would F#'s designers allow it?" I would expect the answer to be "no, they wouldn't".– Alexey Romanov
3 mins ago
else
Consider the following code:
let f a = if a > 5 then true
If you call f 10, it returns true.
f 10
true
Now, ask yourself this: what should f 2 return? I know you're going to say false, but how does the compiler know that? I mean, it's just as likely that you meant it to return true in both cases, isn't it? Or even, perhaps, crash in the a <= 5 case, who knows?
f 2
false
true
a <= 5
So in order for the program to be "complete" (i.e. contain instructions for what to do in every situation), you always have to specify an else branch.
else
unit, however, is special.
unit
Returning unit means that there is no meaningful return value. Essentially unit stands for side-effect: it means that the thing that returned it was meant to produce some effect in the external world. Since F# is not a pure language, such unit-returning things are quite ubiquitous. For example, debug logging:
unit
unit
unit
let f x =
if x < 42 then printfn "Something fishy, x = %d" x
x + 5
With such statements, there is no ambiguity: it's always known that the else branch is meant to return () as well. After all, there are no other values of unit, are there? At the same time, always adding else () at the end would be very tiresome and obfuscating. So, in the interest of usability, the compiler doesn't require an else branch in this specific case.
else
()
unit
else ()
else
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
It has nothing to do with compatibility with OCaml.
– Fyodor Soikin
17 mins ago