Grain is a language built for the modern web by leveraging the brilliant work done by the WebAssembly project.
No runtime exceptions, ever. Every bit of Grain you write is thoroughly sifted for type errors, with no need for any type annotations.
Grain is geared towards functional programming, but understands the web isn't as pure as we would like it to be. Easily write what's appropriate for the scenario.
These work just as you'd expect of any reasonable language.
let someNumber = 5
let someString = "A collection of characters"
Lambdas are king (and by that we mean first-class) in Grain. Here we show the function 'add2' being closed over inside the 'add3' function.
# A simple function that adds two numbers
let add2 = (x, y) => x + y
add2(3, 4)
# A function that adds three numbers with intermediate steps
let add3 = (x, y, z) => {
let firstSum = add2(x, y)
let secondSum = add2(firstSum, z)
secondSum
}
add3(5, 6, 7)
No functional language is complete without recursion (or in this case, mutual recursion).
let rec isEven = (n) =>
if (n <= 1) {
n == 0
} else {
isOdd(n - 1)
}
and isOdd = (n) =>
if (n <= 1) {
n == 1
} else {
isEven(n - 1)
}
isOdd(999)
Sometimes it's best to work as a pair.
let tup = (4, 2)
let (first, second) = tup
first + second
If that's your kind of thing. Of course, we'd prefer to do everything functionally if possible, but it should still be easy to work this way if necessary.
let variable = box 5
let mutateSomeThings = () => {
if (unbox variable > 2) {
variable := (unbox variable) - 2
} else {
variable := (unbox variable) + 2
}
}
mutateSomeThings()
unbox variable # 3 resides in this box
DOM nodes are primitives in Grain. Traditional DOM queries and node operations are available.
let div1 = DOM.query("#div1")
let div2 = DOM.query("#div2")
let div3 = DOM.query("#div3")
DOM.setText(div1, "I'm just a div.")
DOM.setText(div2, "Sitting here on wasm hill.")
DOM.dangerouslySetInnerHTML(div3, "<i>[[grain]]</i>")
Native Grain functions can be bound as callbacks to native DOM events. This example updates a counter whenever the button is clicked.
let counter = box 0
let button = DOM.query("#button1")
let view = DOM.query("#div1")
let handleEvent = () => {
counter := (unbox counter) + 1
DOM.setText(view, toString(unbox counter))
}
DOM.addEventListener(button, "click", handleEvent)
Check out the documentation to learn more, or get started now. If you're interested in getting involed in the development of the language, check out the Grain source.