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





It has nothing to do with compatibility with OCaml.
– Fyodor Soikin
17 mins ago






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.

Popular posts from this blog

PHP contact form sending but not receiving emails

PHP parse/syntax errors; and how to solve them?

iOS Top Alignment constraint based on screen (superview) height