Why Gren?
Gren is a programming language that helps you write simple and correct software.
What does that mean?
Simple
Gren measures simplicity by how many outcomes an operation can have. Take the following code as an example:
In some languages, this can mean a lot of different things. Some languages allow you to override the definition of +
, which means it might execute an arbitrary function. For some languages, this statement can either append one string to another, or add two numbers together. Some languages might even try to convert a
and b
to be the same type, before executing the +
operation.
In Gren, the above statement can only mean one thing: a
and b
are numbers, and the result is that of mathematical addition.
The fact that this statement can only mean one thing is what makes it simple. When reading the code you can be very certain what the result of this operation is, as long as it compiles.
Let’s consider one more example, this one in JavaScript:
Try to answer these questions:
- How many function calls do you see?
- Is the value of
obj
changed by any statement in this function? - Does
a1
equala2
? - What type does this function return?
- Will this function return?
It might surprise you that, without knowing more of the surrounding context, you can’t really answer any of these questions.
- JavaScript has a language feature called getters. This means that a statement like
obj.a
might actually call a function to compute a value. Without knowing howobj
is defined, there’s no way of knowing how many functions will be called. - JavaScript allows mutation. The potential function call
obj.a
, and the actual function callverify(obj)
might end up changing theobj
value. You need to know howobj
andverify
is defined to be certain. - Since
obj
can change, there’s no way to know without knowing howobj
andverify
is defined. In languages that support threads, you also need to know ifobj
is accessible in any other thread. +
works on both numbers and strings. So it probably returns either a number or a string.- Maybe. Any function call can throw an exception.
Let’s pretend the above code was written in Gren, could we answer the same questions with certainty then?
- Gren doesn’t have getters, so the answer is 2 (
verify
and+
). - Gren doesn’t have mutation, so the answer is no.
- Yes, because of (2).
- A number, since
+
only works on numbers. - Gren doesn’t support exceptions, so the answer is yes, if we ignore the possibility of infinite loops and running out of memory.
The simplicity of Gren makes it easier to reason about code. Even when the code in question was written by someone else. The value of simplicity grows along with the size of your code base.
Correct
There are certain constructs that Gren doesn’t have, that are often the source of bugs in other languages. These things are:
- Null
- Exceptions
- Uncontrolled side-effects
What Gren does have is a flexible, although strict, type system which allows you to represent these constructs in a way that lets the compiler help you avoid the most common bugs.
Instead of null
, Gren lets you express the absence of a value by using what is known as a custom type:
This type represents a value which may, or may not, exist. Whenever you try to use this value, the compiler will force you to check if you have a Just
or Nothing
.
The same principle applies to exceptions. Representing an operation which may cause an error is represented by the type:
If a function returns a Result
value, the compiler will force you to handle both the success and the failure condition.
Consider for a moment what this means. Since Gren is statically typed, that means that whenever you see a function which doesn’t return a Maybe
or a Result
type, you can be certain that you’ll always end up with the promised return value.
The same concept applies to side-effects like performing HTTP calls or saving things to disk. A side effect has to be modelled by the type system, and this also means that you have greater insights into the sort of things a third-party package can do.
Conclusion
Gren has made a very specific set of trade-offs that makes it easy to locate and isolate bugs and side effects. These same trade-offs also make the language small in both syntax and concepts. This again reduces the necessary time investment to learn the language, and makes it easy for the compiler to provide detailed and helpful error messages.
These benefits come at the cost of brevity. There’s a chance that other programming languages will allow you to write less code.
It is our belief that as your program grows in complexity and scope, the trade-offs made by Gren make more and more sense.