A guide to Native code and Effect Managers in Elm - Part 1: Commands
Tags: elm, functional
Published: 2020-03-08 22:53:40

---
title: A guide to Native code and Effect Managers in Elm - Part 1: Commands
series: Native code and Effect Managers in Elm
tags: elm, functional
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/zj21et3w78f2eyn4uoci.jpg
published: true
---

This is a guide to understand how Elm implements its core libraries, and how you could write your own.
This article assumes experience writing Elm and JavaScript.

Elm uses a combination of the following resources to implement core libraries (those under the `elm` and `elm-explorations` organisations, like `elm/core` and `elm-explorations/test`):

- Regular Elm code
- Native/Kernel code
- Effect Managers
- Compiler magic

We won't discuss the last one here.
One thing to note is that some packages only use a few of those, for example [`elm/project-metadata-utils`](https://package.elm-lang.org/packages/elm/project-metadata-utils/1.0.0/) is implemented in pure Elm.

>**Note:** Native code and Effect Managers can only be compiled by the [`elm` and `elm-explorations`](https://github.com/elm/compiler/blob/6c19c6e202984e2be98d6abe46b616751f712e94/compiler/src/Elm/Package.hs#L83-L85)[<sup>1</sup>](https://github.com/elm/compiler/blob/5387ae6a1a8a385556492b6f006168e74d0d1e32/compiler/src/Parse/Module.hs#L131-L137)  organisations, so these are out of reach of regular users.
If you still want to use these features, you can use a forked version of the compiler to do so, but I won't discuss that here.

Even if you are not interested in building your own native modules, I still think it's interesting to know how they work, as they are how The Elm Architecture is implemented under the hood.

# Native/Kernel Code

We'll start with Native, or Kernel code. This is the terminology Elm uses for accessing JavaScript code from Elm.

The simplest example of this I could find is the `Debug.log` function from the `elm/core` package:

```elm
Debug.log : String -> a -> a
```

Calling `Debug.log "My label" { a = 2 }` will print `"My label: { a = 2 }"` to the console and will return the same value we passed in as second argument.
If we take a look at the [source code](https://github.com/elm/core/blob/f88d6a6de98802f5cc2d99dc1a0c2734cc5bdd7b/src/Debug.elm#L36-L38), the implementation is just delegating to a function called `Elm.Kernel.Debug.log`:

```elm
-- src/Debug.elm
log : String -> a -> a
log =
  Elm.Kernel.Debug.log
```

If you look through the repository, you won't find a `Elm/Kernel/Debug.elm` module, you'll find [a JavaScript file](https://github.com/elm/core/blob/f88d6a6de98802f5cc2d99dc1a0c2734cc5bdd7b/src/Elm/Kernel/Debug.js) instead. In this file we'll find our sought function:


```javascript
// src/Elm/Kernel/Debug.js
var _Debug_log__DEBUG = F2(function(tag, value)
{
	console.log(tag + ': ' + _Debug_toString(value));
	return value;
});
```

As expected, the [function](https://github.com/elm/core/blob/f88d6a6de98802f5cc2d99dc1a0c2734cc5bdd7b/src/Elm/Kernel/Debug.js#L12-L21) just logs our label and value (after using another javascript function to convert it to a string) and returns it.

> **Note:** In the file above, you can see various functions with a suffix of  `__PROD` and `__DEBUG` in their names. The Elm compiler picks which of those versions you use based on whether you compile your code with optimisations or not: it will use the `__PROD` version for optimised code, and the `__DEBUG` version for unoptimised/debug code.


> **Note:** Kernel modules **must** be defined under the `/Elm/Kernel/` directory hierarchy. From Elm, you can import them as if they were regular modules.
Functions in the native module have to follow the convention of being named like `_MyKernelModule_myFunction`.


```elm
module MyElmModule

-- Imports the kernel module:
-- src/Elm/Kernel/MyKernelModule.js
import Elm.Kernel.MyKernelModule


foo =
    Elm.Kernel.MyKernelModule.myFunction
```

Finally, you **should** give type annotations to kernel functions in Elm, 
if you don't, the compiler will accept whatever type you give it, and you'd be susceptible to runtime exceptions from type errors.

This ends our introduction to Kernel code. If you're interested in some of the more nitty-gritty details, feel free to read the appendix.

# Effect Managers


Effect Managers are a special type of Elm modules that are used to implement commands (like `Random.generate`) and subscriptions (like `Browser.Events.onResize`).
In this article, we'll implement a command from scratch, we'll discuss subscriptions in the next article, as they are a bit more complex.


We'll implement a command (`Cmd`, from now on) that, when dispatched (through a regular `update` function), will display a `window.alert` with a user-selected text.


Here's how an app using it would look like here:


```elm
module Main exposing (main)

-- Our effect manager
import Alert
import Browser
import Html exposing (Html, button, text)
import Html.Events exposing (onClick)


type Msg
    = SendAlert String


view _ =
    button
        [ onClick (SendAlert "Hi there!") ]
        [ text "Click to get an alert" ]


update msg model =
    case msg of
        SendAlert text ->
            ( model, Alert.alert text )


main =
    Browser.element
        { init = \_ -> ( {}, Cmd.none )
        , view = view
        , update = update
        , subscriptions = \_ -> Sub.none
        }
```
_(Also available [here](https://ellie-app.com/7PXv6MpMrHZa1))_

On clicking the button, you would get an alert with the text `"Hi there!"`.

Let's implement the `Alert` effect manager.



## The anatomy of an Effect Manager

Instead of the usual `module MyModule exposing (myFunction)` module declaration, an effect manager starts like this:

```elm
effect module Alert where { command = MyCmd } exposing (alert)
```

Effect managers (which define commands) are required to implement a type (here `MyCmd`, but you can name it however you'd like), and the following functions:

```elm
type MyCmd msg

cmdMap : (a -> b) -> MyCmd a -> MyCmd b

init : Task Never state

onEffects : Platform.Router msg event -> List (MyCmd msg) -> state -> Task Never state

onSelfMsg : Platform.Router msg Never -> Never -> state -> Task Never state
```

Let's go through what each one does, by implementing our `Alert` example.
The `MyCmd` type describes which types of commands our module is capable of producing and performing.

We only offer one command, which only needs to dispatch an alert with a user-selected text, no other information is needed:

```elm
type MyCmd msg = Alert String
```

That was easy.

Now, let's go for `cmdMap`. This function gets used whenever a user calls [`Cmd.map`](https://package.elm-lang.org/packages/elm/core/1.0.4/Platform-Cmd#map) on one of our commands. Given that we don't store a `msg` or anything related to it, our implementation is very simple:

```elm
cmdMap : (a -> b) -> MyCmd a -> MyCmd b
cmdMap _ (Alert text) = Alert text
```

Now we're getting into the more interesting details, we need to implement `init`, `onEffects`, and `onSelfMessage`.

To understand what each of these is for, we need to understand the following: Effect Managers are very similar to Elm applications, they have:

 - A `Model`, usually referred to as `State` in this context
 - An `init` function, which determines the initial `State`, with the only difference being that you're allowed to use a task (and thus, perform side-effects)
 - And finally, _two_ `update` functions: `onEffects` and `onSelfMessage`, we'll discuss them in a minute

For our case, we don't really need to maintain any state, so we can just use an empty record `{}`, and our `init` will be very simple too.

```elm
type alias State =
    {}

init : Task Never State
init =
    Task.succeed {}
```

Finally, `onEffects` and `onSelfMessage` is where the magic starts to happen, we'll ignore for a second its first parameter, the `Platform.Router`.
Our `onEffects` will be called whenever an application dispatches one (or more, through things like [`Cmd.batch`](https://package.elm-lang.org/packages/elm/core/1.0.4/Platform-Cmd#batch)) of our commands, and we receive it in the second argument. Our third argument will receive the current `State`. In this function we're supposed to handle these commands, and update our state if we needed to:


```elm
-- src/Alert.elm
onEffects : Platform.Router msg event -> List (MyCmd msg) -> State -> Task Never State
onEffects router commands state =
    case commands of
        [] ->
            Task.succeed state

        (Alert text) :: rest ->
            let
                _ =
                    Elm.Kernel.Alert.alert text
            in
            onEffects router rest state
```

In words, if we don't have any commands to handle, return the current state (wrapped in a task, because the signature forces us to). Else, handle the first one (in this case we do it by calling a kernel function), and recurse with the rest of the commands.

In case you're wondering, our kernel code for this is unsurprisingly simple (`__Utils_Tuple0` is just a way to return Elm's empty tuple, `()`):

```javascript
// src/Elm/Kernel/Alert.js
function _Alert_alert (text) {
  window.alert(text)

  return __Utils_Tuple0
}
```

For our example, that's basically it! Unfortunately, we do have to implement `onSelfMsg` anyway. Before this, let's understand what the first argument to it and `onEffect` is.

I did say Effect Managers are like regular Elm applications, and while our commands are sort of `Msg`s, we don't control when they're sent, users do. Turns out, it'd really useful to have self-controlled messages as well in these modules, and so we do!

From the type signature above, `event`s are our `msg`s. The router allows us to send ourselves a message, through [`Platform.sendToSelf`](https://package.elm-lang.org/packages/elm/core/1.0.4/Platform#sendToSelf). These events will be routed to our `onSelfMsg` function, and we can use them to update our state. Also, some commands _do_ return messages back to the application, and we can do that with [`Platform.sendToApp`](https://package.elm-lang.org/packages/elm/core/1.0.4/Platform#sendToApp).

Going back to our example, given that we don't really need any self-sent messages, we can set our event type to `Never` and implement `onSelfMsg` in the only way possible:


```elm
type alias Event =
    Never

onSelfMsg : Platform.Router msg Event -> Event -> State -> Task Never State
onSelfMsg _ _ state =
    Task.succeed state
```

----

We've now implemented all the pieces we're required to by the compiler for an Effect Manager, but we're missing the reason why we started implementing our module at all, the `alert` command!

Our first attempt would be to do the following:

```elm
alert : String -> Cmd msg
alert text =
    Alert text
```

But this will give you a type error, `Alert text` is a `MyCmd msg`, not a `Cmd msg`!
Now, remember that strange `where { command = MyCmd }` part of our module declaration? That gives us a magical `command` function that allows us to convert our `MyCmd`s into proper, application-viable `Cmd`s.

```elm
alert : String -> Cmd msg
alert text =
    command (Alert text)
```

And we're finally done!
You can view (but not compile) the full code for this effect manager [here](https://ellie-app.com/7PYDLv78zJha1).

> **Note:** Here, we've used the names `MyCmd`, `MySub`, `State`, `Event`, and so on for the types we've defined, but you can actually pick whatever name you want for each of these, this is just the convention that's typically used in `elm/core`'s effect managers.



# Appendix

## Nuances of interfacing with JavaScript

While this guide is meant to be a more of a resource on *reading* native code, I can give some pointers in case you're interested in writing some.

In regular Elm all functions are curried, and so, functions with multiple arguments really take one at a time and return a function for each one. This is not the case in JavaScript.

To overcome this mismatch, Elm uses a few helper functions on the JavaScript side, going back to our `Debug.log` example, in the [JS source](https://github.com/elm/core/blob/f88d6a6de98802f5cc2d99dc1a0c2734cc5bdd7b/src/Elm/Kernel/Debug.js#L17-L21) you'll see the following:

```javascript
var _Debug_log__DEBUG = F2(function(tag, value)
{
	console.log(tag + ': ' + _Debug_toString(value));
	return value;
});
```

That `F2` function is basically currying the 2-argument function we to passed it so that it can match the way Elm handles function calls. In the source, you'll find functions `F2` through `F9` for converting JavaScript functions with 2 to 9 arguments to a curried version.

Conversely, there are a series of functions called `A2` through `A9` which make calling Elm functions from JS easier:

That means that instead of:
```javascript
// JavaScript
myElmFunction(a)(b)(c)(d)
```

We can use our `A4` helper to invoke this function more naturally:
```javascript
// JavaScript
A4(myElmFunction, a, b, c, d)
```

These functions also perform some optimising tricks to reduce the number of function calls/allocations. If you're interested in that, you can read exactly what they do in the source, [here](https://github.com/elm/compiler/blob/51e20357137ebc9c3f6136cf0a3fe21c24027f39/compiler/src/Generate/JavaScript/Functions.hs#L19-L93).


## Bundling of Kernel code

Some Kernel (JavaScript) code will require using functions from other modules, for this, Elm uses the same `import Module exposing (value)` syntax, in the form of "magic" JS comments.

You can see an example of this in the [`Elm.Kernel.Char` module](https://github.com/elm/core/blob/master/src/Elm/Kernel/Char.js#L1-L5) of the `elm/core` package:

```javascript
/*

import Elm.Kernel.Utils exposing (chr)

*/
```

In that same file, the `chr` function will be accessible as `__Utils_chr`.