@@ -0,0 +1,98 @@
1+# Comparing Custom Types
3+The built-in comparison operators work on a fixed set of types, like `Int` and `String`. That covers a lot of cases, but what happens when you want to compare custom types?
5+This page aims to catalog these scenarios and offer alternative paths that can get you unstuck.
10+It is common to try to get some extra type safety by creating really simple custom types:
16+type Comment = Comment String
17+type Description = Description String
20+By wrapping the primitive values like this, the type system can now help you make sure that you never mix up a `Id` and an `Age`. Those are different types! This trick is extra cool because it has no runtime cost in `--optimize` mode. The compiler can just use an `Int` or `String` directly when you use that flag!
22+The problem arises when you want to use a `Id` as a key in a dictionary. This is a totally reasonable thing to do, but the current version of Elm cannot handle this scenario.
24+Instead of creating a `Dict Id Info` type, one thing you can do is create a custom data structure like this:
27+module User exposing (Id, Table, empty, get, add)
29+import Dict exposing (Dict)
40+ Table Int (Dict Int info)
46+get : Id -> Table info -> Maybe info
47+get (Id id) (Table _ dict) =
50+add : info -> Table info -> (Table info, Id)
51+add info (Table nextId dict) =
52+ ( Table (nextId + 1) (Dict.insert nextId info dict)
57+There are a couple nice thing about this approach:
59+1. The only way to get a new `User.Id` is to `add` information to a `User.Table`.
60+2. All the operations on a `User.Table` are explicit. Does it make sense to remove users? To merge two tables together? Are there any special details to consider in those cases? This will always be captured explicitly in the interface of the `User` module.
61+3. If you ever want to switch the internal representation from `Dict` to `Array` or something else, it is no problem. All the changes will be within the `User` module.
63+So while this approach is not as convenient as using a `Dict` directly, it has some benefits of its own that can be helpful in some cases.
66+## Enumerations to Ints
68+Say you need to define a `trafficLightToInt` function:
71+type TrafficLight = Green | Yellow | Red
73+trafficLightToInt : TrafficLight -> Int
74+trafficLightToInt trafficLight =
78+We have heard that some people would prefer to use a dictionary for this sort of thing. That way you do not need to write the numbers yourself, they can be generated such that you never have a typo.
80+I would recommend using a `case` expression though:
83+type TrafficLight = Green | Yellow | Red
85+trafficLightToInt : TrafficLight -> Int
86+trafficLightToInt trafficLight =
93+This is really straight-forward while avoiding questions like “is `Green` less than or greater than `Red`?”
98+If you have some other situation, please tell us about it [here](https://github.com/elm/error-message-catalog/issues). That is a log of error messages that can be improved, and we can use the particulars of your scenario to add more advice on this page!