class: center, middle, inverse # Why would I ever Elm? ??? This was going to be a more general talk where I introduce Elm in relation to two other things on a "Spectrum of Functional". The left would be fantasy-land (so the most JavaScript way of doing functional), and on the right would be purescript (the most typed functional way of doing functional). But then it was pointed out to me that I'd have to spend all talk introducing these two things, and also why you'd even want to even go so far as to even look at these things. So instead I'm going to jump ahead to why you'd want to introduce functional concepts, in relation to problems that we are probably already having to deal with writing front-end applications, using Elm as an example of something that has these great properties. --- class: center, middle, inverse ## Am I doing functional now? -- ## Isn't JavaScript functional? ??? When writing JavaScript we end up writing functions, so we must be part way to being "functional" already. To find out what is missing I'm going to go through a list of attributes _I_ think functional programming has. Just to repeat: this is not a standard list, I have made it up, feel free to argue with me later on about what is here. --- ## Attributes of functional languages (according to me) - Functions exist as a 1st-class concept ??? That is you can define a function; you can pass a function as a parameter to another function; you can have a function that returns functions. All standard things that we have in JavaScript. -- - Immutable data ??? Instead of mutating the state of something we have functions that take data and return other data, which may or may not be a modified version of the input. Importantly those modifications do not affect the input data but create new data structures. This is how strings work in basically every modern language, but here it is extended that to everything. -- - Side-effects are obvious ??? I think it is really unhelpful to label functional languages as having no side-effects, because if that was the case how would you ever do useful things? Instead it is better to say that side-effects are obvious: there is a consistent way of representing an operation that will cause a network request, say, and since it is explicit there are usually ways of composing side-effects. -- - Union types / ADTs ??? There are usually nice ways to represent choice with "union types" aka "abstract data types". This is a really good way of representing where a user is or what state they are currently in. So for JavaScript we can probably take the first point. If we used a package like immutable-js we could take the second. But the last 2 points are difficult to reconcile with how JavaScript works. --- class: center, middle ## Functions make views safe ??? I'm going to show some examples of how I think applying these ideas can help us with common tasks. I'm going to be comparing with React for the most part, since it is probably the most popular framework, or at least framework style (what with Preact, etc.). My main issue with pretty much every single framework in existence is how views work. My dream is being able to write a view and knowing that all the values referenced exist, all the button clicks will do something, and that I haven't written `dvi`. Elm gives us this, which is why I'm talking about it. --- class: middle ```jsx class HelloMessage extends React.Component { render() { return (
Hello {this.props.name}
); } } ``` .lower-title[Functions make views safe] ??? Here is a pretty basic Hello World component. What happens if `name` doesn't exist? I'm still going to be able to build this and run it in my browser. Then I realise there is a problem, no name is showing up. Elm solves this by making all of my Html elements typed functions. -- ```elm helloMessage : { name : String } -> Html msg helloMessage model = Html.div [] [ Html.text ("Hello " ++ model.name) ] ``` ??? If you ever take a look at the documentation for Elm's Html package you will see a list of functions which take 2 parameters: a list of attributes and a list of children. With this we are able to create type-safe views like the one above. If I failed to pass `name` down a __compile time__ error would happen, so I'd never even spin up my server to try this out. --- class: middle ```jsx ReactDOM.render(
, document.getElementById('root') ); ``` .lower-title[Functions make views safe] ??? The other issue is that maybe I try to pass a non-string down. In my React example, this works fine I just see "Hello 5", which in a more complex app could be bad. -- ```jsx HelloMessage.propTypes = { name: PropTypes.string }; ``` ??? I know React has `propTypes`, which means when an invalid value is provided for a prop, a warning will be shown in the JavaScript console. Great, but I've still spun up my local test server. --- class: middle ```elm view : Html msg view = Html.div [] [ helloMessage { name = 5 } ] ``` *** ```md Function helloMessage is expecting the argument to be: { name : String } But it is: { name : number } Hint: Problem in the name field. ``` .lower-title[Functions make views safe] ??? Elm on the other hand, will not compile this. So functions could help us write safer views, and a compiler that can understand their types can stop us making stupid mistakes. What's next? --- class: middle, center ## Immutability makes change easy to manage ??? I think it should be safe for me to assume that everyone here loves Event Loops? Remember Dave's talk a few months ago about how async and Promises work by putting tasks on a loop? We are going to look at that kind of idea but applied to things you want to do in your application. There has been a big jump, I think, towards "state management" with packages like Redux, or the many variants/wrappers/rip-offs. But the idea Redux brings was inspired by Elm! There is an acronym that if you look into Elm at all will start seeing people mention a lot: TEA. The Elm Architecture. That is just an event loop. Not the Event Loop that NodeJS is running through, but a big loop which moves your application from one state to another. This is totally necessary in Elm because we need a way of changing the state of our application but without mutating anything. --- class: middle ```js const initialState = { count: 0 } const next = (message, prevState) => { switch (message) { 'INC': return { count: prevState.count + 1 } 'DEC': return { count: prevState.count - 1 } } throw new Error(`next doesn't know how to ${message}`) } const state0 = initialState //=> { count: 0 } const state1 = next('INC', state0) //=> { count: 1 } const state2 = next('INC', state1) //=> { count: 2 } const state3 = next('DEC', state2) //=> { count: 1 } const state4 = next('INC', state3) //=> { count: 2 } // ...and so on ``` .lower-title[Immutability makes change easy to manage] ??? This is my rough sketch in JavaScript of what an event loop looks like, minus an actual loop. You have an initial state; and you have a function that takes an event-name/action/message whatever you want to call it, and the last state, and returns the new state. Then the loop part just applies this function over and over again to the previous result with the messages that are created by the outside world / person using the software. This kind of pattern of initial value plus function to calculate the next thing is powerful, and everywhere. --- class: middle ```elm initial : Int initial = 0 type Msg = Increment | Decrement update : Msg -> Int -> Int update msg prevCount = case msg of Increment -> prevCount + 1 Decrement -> prevCount - 1 ``` .lower-title[Immutability makes change easy to manage] ??? I was thinking of showing a Redux example, but I don't really know what that would show vs. just talking about how functions and union types help us out here. If you have any experience with alternatives then this isn't the largest example in the world to imagine in your head. At the top I say what my initial state is going to be, here `0`. Then I define a union type for the things that my program can do. The great thing about it being a union type is I know it can only ever represent one of the values, here `Increment` or `Decrement`, that I say. If you've not seen these before think of it like an enum, but which can't go out of bounds. Then I define the `update` function, a reducer in Redux terms. It takes a message that has happened, the current state (or model, as people would say in Elm-land), and returns our new application state/model is. So we check what the `msg` is, if it is `Increment` we return a new count by adding 1; if `Decrement` subtracting 1. This is the previous example I gave, but in Elm. So it is nicely type-checked and I know there are only ever going to be two different messages to handle, I don't need to throw an error if something unknown happens. --- ```elm initial : Int initial = 0 type Msg = Increment | Decrement update : Msg -> Int -> Int update msg prevCount = case msg of Increment -> prevCount + 1 Decrement -> prevCount - 1 view : Int -> Html Msg view count = Html.div [] [ Html.p [] [ Html.text "Count: ", Html.text (toString count) ] , Html.button [ Html.Events.onClick Increment ] [ Html.text "Up" ] , Html.button [ Html.Events.onClick Decrement ] [ Html.text "Down" ] ] main : Program Never Int Msg main = Html.beginnerProgram { model = initial, update = update, view = view } ``` .lower-title[Immutability makes change easy to manage] ??? And if you wanted to actually make this run we can define the program that links these together with a simple view, then we could do this. Just a note on the use of `beginnerProgram`: 1. I think they are going to change the name in future versions 2. In real life you will generally use `program` because `beginnerProgram` disallows you from causing side-effects.
--- class: center, middle ## What about those explicit side-effects? ??? So we've covered the event loop which allows an immutable language to change state over time with a nice `update` function. But what about side-effects? In the previous example we had an action called `Increment` which we triggered on a button click, and then handled in our `update`. There was no point at which a message we hadn't triggered by user interaction would happen. The way side-effects work in languages which don't really do side-effects is by having a container that says "this is something I want to happen", and then in the case of Elm at least you specify a message to raise when "thing has happened". In other languages there are other ways of doing this, but the Elm way is conceptually quite simple and doesn't require a thousand tutorials on why "Monads are like Burritos". This section is kind of weird and I contemplated deleting it, but it does lead into the bit after, so here goes. --- class: middle ```elm update : Msg -> Model -> (Model, Cmd Msg) update msg model = case msg of FetchPosts userId -> (model, Http.send PostsFetched (getPosts userId)) PostsFetched newPosts -> ({ model | posts = newPosts }, Cmd.none) ```
Compare with the previous `update` ```elm update : Msg -> Int -> Int update msg prevCount = case msg of Increment -> prevCount + 1 Decrement -> prevCount - 1 ``` .lower-title[What about those explicit side-effects?] ??? It looks a bit like this. You end up splitting it in to two parts, most of the time. First we have the message to trigger fetching the posts for a user from a backend API. The return type for our `update` has been extended to include a `Cmd Msg`, basically a command for the Elm runtime to execute that also says what `Msg` to raise when done. That is our call to `Http.send` which says, ok Elm pls go do the request and then when you are done use `PostsFetched` to tell me the result. Once Elm is done we come back in to the `update` function with the `PostsFetched` message, and are able to update the model with the user's new posts. We don't want the runtime to do any additional fetches or anything so we send the new model back with a `Cmd.none`. And that is kind of it. Any time you want to change the outside world you will end up calling a function that returns a `Cmd`, and Elm will handle it for you. --- class: middle ```elm type alias Model = { items : List String } type Msg = NewItem String update : Msg -> Model -> (Model, Cmd Msg) update msg model = case msg of NewItem item -> ({ model | items = item :: model.items }, Cmd.none) subscriptions : Model -> Sub Msg subscriptions model = WebSocket.listen "ws://localhost/items" NewItem ``` .lower-title[What about those explicit side-effects?] ??? The other half to triggering side-effects is being notified of changes to the outside world. For instance a timer that needs updating every second, or a feed that gets data pushed from a websocket. This is solved by a subscription. In Elm, because they love these three letter abbreviations for things, a `Sub`. It works a lot like the command before, you need to have a message that your update handles, and then you tell Elm to subscribe to something and tell you about it. --- class: middle, center ## Union types for representing states ??? As developers we probably recognise that 90% of the time what we are dealing with is a state-machine. But the languages we choose to write in are very bad at representing them, so we hardly ever reach for a state-machine, and instead opt for sticking a few bools on our objects. Take the Http request for a user's posts in the previous example. The request can be in a few states which we may want to represent to the user. 1. We haven't requested any data because we don't know who the user is. 2. We have made the API request and are waiting for the response, may want to indicate that the data is loading with a spinner. 3. The request is done and it either worked (so we can show the user their posts), or it failed (so we could show a nice error message, or log the details for later analysis). If we take the "simple" boolean approach to modeling this we may get something like, --- class: middle ```js class PostsRequest { constructor(userId) { this.posts = [] this.isDone = false this.isLoading = false this.isSuccess = false } get() { // do the request and keep all of the booleans correct } } ``` .lower-title[Union types for representing states] ??? So now we could have our controller/view/component set this off and check the booleans to know what to display. But it isn't great because if it is successful or not then we know it isn't loading. So maybe 2 booleans are not what we want, instead we want something with 4 states. That's what XMLHttpRequest kind of does with `readyState`. Value|State -----|----- 0|UNSENT 1|OPENED 2|HEADERS_RECEIVED 3|LOADING 4|DONE You just need to remember that a 3 is loading, 4 is done, etc. --- class: middle ```elm type PostsRequest = Initial | Loading | Success | Failure ``` .lower-title[Union types for representing states] ??? In Elm we can put our possible request states into a nice union type. If we put this in our application's model we know it will only ever have one of these values. We saw this before with the `Msg` that could be `Increment` or `Decrement`. --- class: middle ```elm type PostsRequest = Initial | Loading | Success (List Post) | Failure Error ``` .lower-title[Union types for representing states] ??? The thing that makes union types so much more powerful than enums (apart from you can't get one out of bounds), is that data can be associated with one value and not others. So here we get to say that if the request is in it's `Initial` or `Loading` state then there are no posts, if it is successful then there is a list of posts, and if it failed then there is an error. --- class: middle ```elm initial : Model initial = { request = Initial } update : Msg -> Model -> (Model, Cmd Msg) update msg model = case msg of FetchPosts userId -> ({ request = Loading }, Http.send PostsFetched (getPosts userId)) PostsFetched response -> case response of Ok posts -> ({ model | request = Success posts }, Cmd.none) Err error -> ({ model | request = Failure error }, Cmd.none) ``` .lower-title[Union types for representing states] ??? We can take the `PostsRequest` type and rewrite our update from before to use it. This isn't that impressive, we are just passing it around and keeping our model in sync with how the request is doing. What is cool is how we can write the view. --- class: middle ```elm view : Model -> Html msg view model = case model.request of Initial -> Html.button [] [ Html.text "Log-in" ] Loading -> Html.div [] [ spinner ] Success posts -> Html.ul [] (List.map viewPost posts) Failure error -> Html.div [] [ errorToHumanFriendlyDescription error ] ``` .lower-title[Union types for representing states] ??? Here it is so so obvious how we are handling each state our request can be in. And the Elm compiler will force us to handle all the cases, we couldn't just forget to define how to display the `Loading` state, for instance. --- ## Conclusion - Functions mean our views are just code - Typed functions mean our views work - Commands make working with side-effects explicit - Union types make modeling our application state easy ??? Applying functional ideas to our front-end applications makes writing them easy. I hope to see more stealing of ideas from Elm in our JS packages, because it will make developing complex things so much better. --- class: middle # Workshop ##