New BuckleScript Syntax
BuckleScript 8.1 comes with a brand new syntax parser and printer that allows for much better syntax error messages and other benefits we will talk about soon.
More details about the new syntax can be found in this early announcement blog post.
This document gives an overview over the most relevant features until more details / docs are revealed.
Note: In case you are looking for the current Reason language documentation (v3.6), you can find it here.
What is Different to Reason v3.6?
Complete removal of semicolon (you can still write them).
No need for parentheses around
if
,switch
andtry
.Type arguments: from
option(int)
tooption<int>
.Interpolated string: from
{j|hello ${name}|j}
toj`hello ${name}`
.Polymorphic variants: from
`red
to#red
.Arrays: from
[|1,2,3|]
to[1,2,3]
. In JS, arrays are the right default.Lists: from
[1,2,3]
tolist[1,2,3]
. This ties with upcoming plans to access containers in a uniform way:set[...]
andmap[...]
. Maybe temporary.Exception: from
try (compute()) { | Not_found => Js.log("oops")}
totry compute() catch { | Not_found => Js.log("oops")}
.First class module: from
(module S: Student)
tomodule(S: Student)
.No custom infix operator for now (including
mod
).Object access: from
settings##visible #= true
tosettings["visible"] = true
. Rejoice!Object: from
Js.t({"age": int})
to just{"age": int}
. TheJs.t
part is now implicit.Attribute: from
[@bs.deriving accessors]
to@bs.deriving(accessors)
. From[%re bla]
to%re(bla)
.Removed dereference syntax
result^
. Just useresult.contents
.`hello world`
for multiline strings."hello world"
string is now singleline.fun
pattern matching syntax removed.Type declaration is non-recursive by default, consistent with let bindings. To have recursive types, use
type rec myList<'a> = Nil | Cons('a, myList<'a>)
.Use any words, including reserved keywords, as your identifier name:
let \"try" = true
.
How to Use the New Syntax
Install bs-platform@8.1
and create a file with the .res
or .resi
file extension to enable the new syntax parser (no further configuration required).
Quick Example
RESif hasEaten {
Js.log("more dessert please")
} else {
Js.log("dessert please")
}
let message = j`Hello ${userName->Js.String.toUpperCase}!`
type student<'extraInfo> = {
name: string,
age: int,
otherInfo: 'extraInfo,
}
@bs.val external window: {..} = "window"
window["addEventListener"]("focus", onFocus)
Comparison to JS
Let's have a look on how different JS constructs look in our new syntax:
Comments
JavaScript | Us |
---|---|
/* Comment */ | Same |
// Line comment | Same |
Variable
JavaScript | Us |
---|---|
const x = 5; | let x = 5 |
var x = y; | No equivalent (thankfully) |
let x = 5; x = x + 1; | let x = ref(5); x := x.contents + 1 |
String & Character
JavaScript | Us |
---|---|
"Hello world!" | Same |
'Hello world!' | Strings must use " |
"hello " + "world" | "hello " ++ "world" |
`hello world` | Same |
Boolean
JavaScript | Us |
---|---|
true , false | Same |
!true | Same |
|| , && , <= , >= , < , > | Same |
a === b , a !== b | Same |
No deep equality (recursive compare) | a == b , a != b |
a == b | No equality with implicit casting (thankfully) |
Number
JavaScript | Us |
---|---|
3 | Same * |
3.1415 | Same |
3 + 4 | Same |
3.0 + 4.5 | 3.0 +. 4.5 |
5 % 3 | mod(5, 3) |
* JS has no distinction between integer and float.
Object/Record
JavaScript | Us |
---|---|
no types | type point = {x: int, mutable y: int} |
{x: 30, y: 20} | Same |
point.x | Same |
point.y = 30; | Same |
{...point, x: 30} | Same |
Array
JavaScript | Us |
---|---|
[1, 2, 3] | Same |
myArray[1] = 10 | Same |
[1, "Bob", true] | (1, "Bob", true) * |
* Heterogenous arrays in JS are disallowed for us. Use tuple instead.
Null
JavaScript | Us |
---|---|
null , undefined | None * |
* Again, only a spiritual equivalent; we don't have nulls, nor null bugs! But we do have an option
type for when you actually need nullability.
Function
JavaScript | Us |
---|---|
arg => retVal | Same |
function named(arg) {...} | let named = (arg) => {...} |
const f = function(arg) {...} | let f = (arg) => {...} |
add(4, add(5, 6)) | Same |
Blocks
JavaScript | Us |
---|---|
|
|
If-else
JavaScript | Us |
---|---|
if (a) {b} else {c} | if a {b} else {c} |
a ? b : c | Same |
switch | switch but super-powered pattern matching! |
* Our conditionals are always expressions! You can write let result = if a {"hello"} else {"bye"}
Destructuring
JavaScript | Us |
---|---|
const {a, b} = data | let {a, b} = data |
const [a, b] = data | let [a, b] = data * |
const {a: aa, b: bb} = data | let {a: aa, b: bb} = data |
* Gives good compiler warning that data
might not be of length 2.
Loop
JavaScript | Us |
---|---|
for (let i = 0; i <= 10; i++) {...} | for i in 0 to 10 {...} |
for (let i = 10; i >= 0; i--) {...} | for i in 10 downto 0 {...} |
while (true) {...} | while true {...} |
JSX
JavaScript | Us |
---|---|
<Foo bar=1 baz="hi" onClick={bla} /> | Same |
<Foo bar=bar /> | <Foo bar /> * |
<input checked /> | <input checked=true /> |
No children spread | <Foo>...children</Foo> |
* Argument punning!
Exception
JavaScript | Us |
---|---|
throw new SomeError(...) | raise(SomeError(...)) |
try {a} catch (Err) {...} finally {...} | try a catch { | Err => ...} * |
* No finally.
Blocks
The last expression of a block delimited by {}
implicitly returns (including function body). In JavaScript, this can only be simulated via an immediately-invoked function expression (since function bodies have their own local scope).
JavaScript | Us |
---|---|
|
|