A new release of eco compiler and runtime for building native applications in Elm is available:
What is eco ?
eco is Elm Compiler Optimized, a compiler that aims to be 100% Elm compatible and can compile Elm code to run natively on x86 or Arm platforms, supporting Linux, Mac and Windows.
What is new in this release ?
All of the elm/* packages are ported, with their kernels re-implemented in C++.
There is an official system package providing support for lots of Posix-ish APIs, as well as for running web servers, including the server end of websockets.
This also has Streams over the same Bytes type as elm/bytes for streaming IO.
The Streams concept and many parts of the eco/system package were copied from Gren with permission from Robin Heggelund Hansen.
How does this release improve on 0.1.0
The 0.1.0 alpha release was less mature, and IO could only be done through its exposed internal compiler API eco/kernel, which was never intended to be a public API.
The 0.2.0 release is a significantly better compiler and runtime:
- Overall performance was improved roughly 4x.
- The garbage collector was greatly improved, with a tenured nursery, and concurrent mark and sweep, much better pause times, and most GC work kept off the main program thread.
- Some formal verification work was done on the threaded GC by modelling it in TLA+
- Compile times are better, although there is still work to be done here.
- A significant new compiler optimization called Lambda Set Substitution was introduced, which eliminates most dynamic dispatches for higher order function calls.
- Many smaller optimisations added.
What can I do with it ?
You can build server side applications, talking HTTP or Websockets or raw TCP or UDP, TLS is also supported. I have built a game server that serves the game over HTTP or Websockets for example.
You can build native applications with ports, and use that mechanism to implement any kind of native application you wish. Zero-copy Bytes over ports is supported with an API in C++ that helps to eliminate common mistakes.
You can re-use existing Elm code and packages to do this.
Does it do reference counting or optimistic mutation ?
No, the heap is only garbage collected in 0.2.0. Functional-but-in-place optimisation will be the subject of a later release.
So how fast is it really ?
The benchmark results are not spectacular overall, yielding roughly a 1.6x speed up compared with Javascript running on Node, generated with Elm 0.19.1, but there is a clear trend in those results.
Benchmarks that do not use kernel functions and are compute oriented, speed up maybe 5x to 10x over JS. Benchmarks using kernel functions do less well, and are even slower in some cases.
The reason for poor kernel function performance is partly that little effort has gone into optimizing them yet, and that most optmizations do now flow accross from Elm into C++. For example, a C++ kernel function cannot be inlined into Elm code.
This will be addressed in later releases, with kernel functions becoming part of ecos MLIR dialect, or by compiling the C++ into LLVM IR and then optimizing all the LLVM IR together. The MLIR dialect route will make use of MLIR as templates, allowing monomorphization, inlining, lambda sets and other optimizations to flow accross the kernel boundary.
What other exciting features are in the pipeline ?
- Support for multi-threaded Elm with actor model concurrency.
- A reflection API built on runtime type information. (RTI already exists to allow Debug.log to know how to print any value given to it.)
- A formal language specification and conformance test suite.
- A package server for sharing packages that build on eco/system and that acts as a mirror of https://package.elm-lang.org/ for redundancy when GitHub fails.
- Porting of all of the elm-explorations/* packages.
Where can I learn more ?
The roadmap is up to date with my current thinking at this time.
The code is documented with a Program Theory, Peter Naur style, and much of that has been written up in the Docs section on the website, start here: