FAQ and design rationale
About the project#
Why fork Gren instead of contributing to it?#
Geng changes things that every Gren program depends on: Int becomes exactly
32 bits, == becomes a class method, Cmd and Sub are removed, and
strings stop exposing UTF-16. Those changes are what make one program mean
the same thing on JavaScript, the BEAM and native code, and they are not
compatible with existing Gren code.
Why not Haskell, OCaml, F#, Gleam or Roc?#
Each of them is a good language. None of them gives both of the things Geng is for: a small language whose programs cannot crash on a null, an unhandled error or a missing case, and one program that means the same thing on JavaScript, the BEAM and native code.
- Haskell is pure and checks a great deal, but it is a large language: higher-kinded types, type-level programming and many extensions. Code can read like a different language per author. Lazy evaluation also makes memory use hard to predict. Haskell does not run on the BEAM.
- OCaml and F# have exceptions and mutable variables, and F# has
nullfrom .NET, so the guarantees are conventions, not checks. Neither runs on the BEAM, and F# runs where .NET runs. - Gleam is the closest relative: a typed language for the BEAM and
JavaScript. It has no native target, and its
Intis arbitrary-precision on the BEAM but a JavaScript number in the browser, so the same program can give different answers on its two platforms.panicandlet assertend a program from ordinary code. - Roc compiles to native code and WebAssembly, but not to the BEAM or JavaScript.
Geng starts from Gren, and Gren from Elm, because they already had the small language and the clear compiler errors. What Geng adds is the specification that makes the platforms agree: fixed integer sizes, its own float printing and math functions, and one conformance suite for every backend.
What does “Geng” mean?#
It is the Thai word เก่ง, which means “skilled” or “capable”. The G is hard, as in “Go”, not soft, as in “Java”.
Is it ready for production?#
No. See Status and roadmap.
Language design#
Why classes, but no Functor or Monad?#
Classes were added for specific problems: custom types as Dict keys,
== on functions being a compile error instead of a crash, and arithmetic
over ten numeric types without ten copies of every function. Classes are
limited to one type parameter and there are no higher-kinded types, which
keeps type checking decidable and error messages understandable, and keeps
code from turning into a different language per author.
Why no mutation, even locally?#
Because a value that can never change can be shared with another task, process or thread without a lock or a copy. On the BEAM this is how the runtime already works; on other platforms it removes data races by construction.
When building a large array, an Array.Builder writes into one buffer in
place, but nothing can see that happen: the compiler checks that a builder
is used only once, so no one else holds it. See
Builders.
Why no exceptions?#
An exception is control flow that does not appear in any type. In Geng, a
function that can fail returns a Maybe, a Result or a failing Task, and
the compiler makes the caller handle it. See
Error handling.
Why is Int 32 bits?#
Because it has to behave the same everywhere, and 32 bits is cheap on every
platform: JavaScript has fast 32-bit integer arithmetic, and native code and
the JVM have it built in. A 64-bit Int would force JavaScript onto BigInt,
which is much slower. Int64, UInt32 and UInt64 are available when you
need them, and they map directly to protobuf’s integer types.
Why no tuples?#
Gren removed them, and Geng follows. A record with named fields says more than a tuple with positions.
Why can’t I define my own operators?#
Custom operators are a common source of code that only its author can read. The fixed set is enough for arithmetic, comparison, pipelines and composition. See Operators.
Why is there no exposing (..)?#
With import A exposing (..), the names in scope depend on the version of
A. If A adds a function in a minor release whose name you also import
from somewhere else, your code stops compiling, even though neither you nor
A’s author did anything wrong. Listing names explicitly prevents this, and
tells readers where each name comes from.
exposing (Type(..)) is still allowed, because a type’s constructors can
only change in a breaking release anyway.
Platforms#
Is the same program really identical on every platform?#
That is the goal, and it is tested. Every backend runs the same conformance
suite, whose expected outputs are written by hand from the specification.
Where the platform would give different answers, Geng specifies the answer
itself: integers have fixed sizes and wrapping, floats follow IEEE 754 even
on the BEAM, sin and float printing are implemented in Geng, and Unicode
tables come from a fixed Unicode version. What does differ between platforms
is speed.
Why the BEAM?#
It was built to run systems that must not go down: millions of lightweight processes, isolation between them, supervisors that restart what fails, and upgrades of running code. It is the right platform for the coordination part of a distributed system. Erlang and Elixir are dynamically typed; Geng offers the same platform with a strict type system, and the same code can run elsewhere.
Which platform should I use?#
Practical#
How do I debug without print statements?#
Debug.log prints a value and returns it, in development builds. inspect
turns any value into a string and can be used anywhere, including in
production code.
Is there a REPL?#
No. A REPL would have to pick one backend to evaluate on, and Geng has several.
How fast is Geng?#
Native code is faster than Node.js on most of the workloads measured: about
1.5× on a Dict updated in a loop, 2.4× on counting words, and 3× on the
compiler’s own formatter and C backend. Math functions such as sin and
log are 4× to 9× faster natively than on JavaScript.
On JavaScript, some operations are slower than in Gren, such as 64-bit integers and math functions, because they give the same answer on every platform.
Can I use Geng with my existing codebase?#
See Interop.
Is there editor support?#
Not yet.
Where is the standard library documentation?#
Which packages form the standard library has not been decided. See Status and roadmap.