on daa0796 help sign in
elk/hints/missing-patterns.md
139 lines 4.0 kB history raw
2# Hints for Missing Patterns
4Elm checks to make sure that all possible inputs to a function or `case` are handled. This gives us the guarantee that no Elm code is ever going to crash because data had an unexpected shape.
6There are a couple techniques for making this work for you in every scenario.
9## The danger of wildcard patterns
11A common scenario is that you want to add a tag to a custom type that is used in a bunch of places. For example, maybe you are working different variations of users in a chat room:
13```elm
14type User
15 = Regular String Int
16 | Anonymous
18toName : User -> String
19toName user =
20 case user of
21 Regular name _ ->
22 name
24 _ ->
25 "anonymous"
26```
28Notice the wildcard pattern in `toName`. This will hurt us! Say we add a `Visitor String` variant to `User` at some point. Now we have a bug that visitor names are reported as `"anonymous"`, and the compiler cannot help us!
30So instead, it is better to explicitly list all possible variants, like this:
32```elm
33type User
34 = Regular String Int
35 | Visitor String
36 | Anonymous
38toName : User -> String
39toName user =
40 case user of
41 Regular name _ ->
42 name
44 Anonymous ->
45 "anonymous"
46```
48Now the compiler will say "hey, what should `toName` do when it sees a `Visitor`?" This is a tiny bit of extra work, but it is very worth it!
51## I want to go fast!
53Imagine that the `User` type appears in 20 or 30 functions across your project. When we add a `Visitor` variant, the compiler points out all the places that need to be updated. That is very convenient, but in a big project, maybe you want to get through it extra quickly.
55In that case, it can be helpful to use [`Debug.todo`](https://package.elm-lang.org/packages/elm-lang/core/latest/Debug#todo) to leave some code incomplete:
57```elm
58type User
59 = Regular String Int
60 | Visitor String
61 | Anonymous
63toName : User -> String
64toName user =
65 case user of
66 Regular name _ ->
67 name
69 Visitor _ ->
70 Debug.todo "give the visitor name"
72 Anonymous ->
73 "anonymous"
75-- and maybe a bunch of other things
76```
78In this case it is easier to just write the implementation, but the point is that on more complex functions, you can put things off a bit.
80The Elm compiler is actually aware of `Debug.todo` so when it sees it in a `case` like this, it will crash with a bunch of helpful information. It will tell you:
82 1. The name of the module that contains the code.
83 2. The line numbers of the `case` containing the TODO.
84 3. The particular value that led to this TODO.
86From that information you have a pretty good idea of what went wrong and can go fix it.
88I tend to use `Debug.todo` as the message when my goal is to go quick because it makes it easy to go and find all remaining todos in my code before a release.
91## A list that definitely is not empty
93This can come up from time to time, but Elm **will not** let you write code like this:
95```elm
96last : List a -> a
97last list =
98 case list of
99 [x] ->
100 x
102 _ :: rest ->
103 last rest
104```
106This is no good. It does not handle the empty list. There are two ways to handle this. One is to make the function return a `Maybe` like this:
108```elm
109last : List a -> Maybe a
110last list =
111 case list of
112 [] ->
113 Nothing
115 [x] ->
116 Just x
118 _ :: rest ->
119 last rest
120```
122This is nice because it lets users know that there might be a failure, so they can recover from it however they want.
124The other option is to “unroll the list” one level to ensure that no one can ever provide an empty list in the first place:
126```elm
127last : a -> List a -> a
128last first rest =
129 case rest of
130 [] ->
131 first
133 newFirst :: newRest ->
134 last newFirst newRest
135```
137By demanding the first element of the list as an argument, it becomes impossible to call this function if you have an empty list!
139This “unroll the list” trick is quite useful. I recommend using it directly, not through some external library. It is nothing special. Just a useful idea!