Case for if-then-else
I mostly do not use
if-then-else. Part of this is just a common Elm feeling of desiring to keep the language small, and since we have case expressions we do not really need
if-then-else. But there is another part to it, I can order the branches anyway I like, I do not have to have the
True branch first. Why would I wish to do this?
My feeling is that as you’re reading code, there is only so much you can keep on your “stack”. So if you have a large branch of an
if-then-else and a small trivial one, I tend to place the small trivial one first.
This is kind of similar to defining a recursive function in which you do the base-case first, since the base-case is often quite trivial.
So for example, suppose you are rendering a sidebar menu that may or may not be open:
showSideBar : Model -> Html Msg showSideBar model = if model.sideBarOpen then Html.div [ Attributes.id "side-bar" ] [ .... ... many lines of code ] else Html.nothing
I find if you read down to the
else expression this way you have typically forgotten what the condition was and you have to scan/scroll back up to remind yourself what it was. There are three ways you can get around this:
Negate the condition
showSideBar : Model -> Html Msg showSideBar model = if not model.sideBarOpen then Html.nothing else Html.div [ Attributes.id "side-bar" ] [ .... ... many lines of code ]
Factor out the ‘then’ branch
showSideBar : Model -> Html Msg showSideBar model = let viewOpenSideBar = Html.div [ Attributes.id "side-bar" ] [ .... ... many lines of code ] in if model.sideBarOpen then viewOpenSideBar else Html.nothing
Case and re-order
showSideBar : Model -> Html Msg showSideBar model = case model.sideBarOpen of False -> Html.nothing True -> Html.div [ Attributes.id "side-bar" ] [ .... ... many lines of code ]
The final one of these seems more genuine to me, you’re writing what you mean. Often the factoring out can also be useful, but I find that, you often need to think of two names which basically mean the same thing. Negating the condition is fine, but it’s not the original question I was asking. It reads strangely, in this case it reads as “is the sidebar not open?”, but it’s clearly not a bad solution.
I prefer the final version, it reads nicely: “Is the side bar open? If not then draw nothing, otherwise ….”, and because you’ve got that condition off your stack you can forget about it and concentrate on the intersting code that is drawing the side bar.
So I typically use
if-then-else because I can re-order the branches if I feel it reads better. It also means if I need to change the type of the condition there is less to change. A common change of type is changing between
Maybe, so I might have something like:
case mUser of Nothing -> Html.nothing Just user -> .. draw something ..
I then later realise that the
draw something does not actually use the
user, I just need to know that the user is logged in, it doesn’t matter who they are logged in as, in which I might change this to:
case Maybe.isSomething mUser of False -> Html.nothing True -> .. draw something ..
Or I might have started with this version and then realise I need the actual
user value for something. Either way changing between the two is easier because I’m habitually using
case-of instead of
There is one good reason to sometimes favour using
if-then-else, they do not increase indentation, so if you have several nested boolean conditionals, it might be tidier to use
if-then-else. Still I cannot remember the last time that happened for me.