Skip to content

Writing Native

Noah edited this page Jan 1, 2016 · 17 revisions

What is Elm Native?

Javascript! Straight up Javascript, wrapped in a framework. It's not type checked, it runs on a Javascript engine just like JQuery. It doesn't even have to be Javascript, it can be a compile-to-Javascript language, as long as the compile step takes place before Elm's compile step.

Should I be writing Native?

If possible, avoid writing Native. See these two threads here and here for further information.

What does it look like?

For a basic example, check out how to write your first Native module

The theory

Every Native module has a standard that it needs to follow. First, it must export itself by attaching to the global Elm object. Native should attach to Elm.Native, non-native should attach to just Elm. We must then define our module, by creating an empty object with the attribute make. make should be a function that takes an instance of the Elm object, and returns an object where each property can be accessed through the Elm code.

It should also check to see if the current module is already defined to have a values property on the instance of Elm passed in. If it does, simply return that instead. These are the values that have been loaded already.

Within the make function, it is possible to to use other modules. To do this, we run the make function, passing in the Elm instance. From there the module's attached properties can be used just as if it were in Elm code itself.

var make = function make(localRuntime) {
    localRuntime.Native = localRuntime.Native || {};
    localRuntime.Native.Http = localRuntime.Native.Http || {};

    if (localRuntime.Native.Http.values) {
        return localRuntime.Native.Http.values;
    }

    var http = require('http');
    var fs = require('fs');
    var mime = require('mime');

    var Task = Elm.Native.Task.make(localRuntime);
    var Utils = Elm.Native.Utils.make(localRuntime);
    var Signal = Elm.Native.Signal.make(localRuntime);
    var Tuple0 = Utils['Tuple0'];
    var Tuple2 = Utils['Tuple2'];

    return {
        'createServer': createServer(fs, http, Tuple2, Task),
        'listen': F3(listen(Task)),
        'on': F2(on(Signal, Tuple0))
    };
};
Elm.Native.Http = {};
Elm.Native.Http.make = make;

Elm internals

There can be considered two parts to Elm:

  • Elm.Native
    • Native code, written by humans!
    • Follows a standard structure
    • N.B: must have "native-modules": true in elm-package.json for it to be included
  • Elm
    • Generated code, compiled from code written in Elm the language

This can be broken down further, into

  • The Elm runtime/core
    • Provided by the core library for elm
    • Contains a standard set of modules which are included in every Elm project
    • Also provides bootstrapping and setup for the framework
  • Extra Elm modules
    • Anything that isn't part of core

Note that Elm modules could have native extensions that overwrite core libraries. This is how some meta-programming in Elm is achievable.

Now check out:

Clone this wiki locally