Hungarian notation and Elm maybes.

· Allanderek's blog


There is an old but excellent post from Joel on Software which defends hungarian notation. Briefly hungarian notation was mis-applied in many places, and so something that wasn't nearly as useful as hungarian notation was adopted and then (rightly) despised. That post is great and worth reading if you haven't, but it is also quite long, so I'm going to first of all explain the correct hungarian notation that is useful, then the incorrect despised hungarian notation. Finally, I'm going to end by discussing how the old despised hungarian notation relates to Elm maybes.

Correct hungarian notation #

The idea is that some types are the same, but refer to different kinds of things. The standard example was a length specified in particular units, which might be, cm, px, or ch (centimeters, pixels, or characters). So the idea with hungarian notation is, if you have a variable name that represents a length, prefix the name with a prefix that specifies the units. So you might have:

1let
2    pxScreenWidth = pxGetScreenWidth(..)
3in
4max pxScreenWidth player.pxHorizontalPosition

The idea is, that if you make a mistake, this should be noticable to anyone reading the code:

1let
2    pxScreenWidth = pxGetScreenWidth(..)
3in
4max pxScreenWidth player.cmHorizontalPosition

Just by looking at this, you know there is some mistake in the code. It might be that pxGetScreenWidth does actually return the screen width in centimeters, but then it is mis-named. Or it could be that player.cmHorizontalPosition does actually hold the horizontal position in pixels, but then that is mis-named. More likely, you're trying to combine two measurements in different units and that just doesn't make sense to do.

Now, of course, with a type system a bit more expressive than C's, you could get the compiler to help you out here. You can create new types for lengths in each of the three (or however many there are) units of measurements, and then you wouldn't be able to mix and match. That's one reason you don't tend to see hungarian notation in Elm code. However, another reason is that hungarian notation got warped, and disliked.

Incorrect hungarian notation #

Unfortunately, there was a mistake in the use of hungarian notation, in which instead of the 'kind' of the variable in question, the literal type of the variable was written as the prefix. So the above would become:

1let
2    intScreenWidth = intGetScreenWidth(..)
3in
4max intScreenWidth player.intHorizontalPosition

Which of course is utterly useless in helping you to spot coding errors. If you're wondering how anyone could possibly make such a mistake as this, remember that this was popularised in C, where you have a few different types that all represent an integer: char, unsigned char, short, unsigned short, int, unsigned int, long, unsigned long, at least. So I guess there was some idea that this had some use. Still, this form of hungarian notation was mostly just baggage, which didn't really help you spot mistakes, and in fact made a bunch of variable names look similar, and also made it difficult to change the type of a variable. It was rightly disliked and fell out of fashion.

Joel (on Software) put this mistake down to Simonyi's use of the word type (rather than say kind) and popular Windows programming books like Charles Petzold's.

Hungarian Notation and Elm Maybes #

Okay, so what does this have to do with Maybe types in Elm? I find myself sort of using this style of naming variables, but for a different reason. I regularly prefix my variable name with an m if it is a Maybe type. So I might do something like the following:

1showUser : Maybe User -> Html msg
2showUser mUser =
3    ...

The compiler of course will prevent me from using the value mUser as a straight-up User type, so why would I bother? Well, it's about finding names, to implement my showUser function, I probably have to pattern match on the Maybe and then find a name for the resulting Just argument:

 1showUser : Maybe User -> Html msg
 2showUser mUser =
 3    case mUser of
 4        Nothing ->
 5            Html.text "Anonymous"
 6        Just user ->
 7            Html.span
 8                []
 9                [ Html.text user.name
10                , Html.text " ("
11                , Html.text user.email
12                , Html.text ")"
13                ]

Had I named the original mUser just user I'd be stuck for a decent name for Just ....