-
-
Notifications
You must be signed in to change notification settings - Fork 16
Native best practices
Native is dangerous. It can introduce runtime exceptions into your code. For that reason, we have a set of best practices when writing Native code.
You can bring things in from Native as Json.Value. This is better than bringing them in without
TODO: expand with examples
Input types from Elm are compile-time checked, outputs from Native code is not. As a rule, always make sure that your function will return the same type for a given object.
The following function is fine, as the Elm code guarantees that the function will only receive an int.
var add = function(n){
return n + n;
}; add : Int -> IntThe following function is not
add : a -> aIt will work fine for Int, String, Float, etc. But as soon as it's given any other type for which there is no + defined in Javascript, it will crash.
-- this will work fine
four = add 2
-- this too
nana = add "na"
-- this will kill the type system at _runtime_
oops = add Nothing
The following function is not okay
var select = function(query) {
return document.querySelector(query);
};select : String -> NodeThe problem comes from the fact that document.querySelector returns null when it fails to find anything. Elm won't complain, as the Elm code will wrap the null with the type Node. The problem will come when you then try to use a Node in another function. You will get a null error.
-- no error here
nullNode : Node
nullNode = select "doesntexist"
-- this will die, and introduce a runtime exception
-- causing the runtime to die
content = getAttribute "content" nullNode
Instead, check for null and return a maybe.
var select = function(query) {
var node = document.querySelector(query);
if (node === null) return Maybe.Nothing;
return Maybe.Just(node);
};select : String -> Maybe NodeSee https://github.com/elm-lang/core/issues/453#issuecomment-161050745
There's no real way outside of Tasks to signify when a function is impure in Elm. So, let's use Task everywhere!
activeElement : Task x QueryNode
activeElement =
Native.Query.activeElementDon't do
import Native.MyNative
import MyOtherdo
import MyOther
import Native.MyNativeThe reason here is that occasionally, in some cases, if you use the incorrect import order, it will cause Elm to crash at runtime (albeit in a vocal way). We're currently unable to figure out why this happens, but it happens in this case here