Berkenalan dengan ReasonML

JavaScript adalah dynamic language yang singkatnya type dari suatu variable tersebut berdasarkan nilai nya. Yang artinya, tipe data pada variable mengikuti nilainya, bukan sebaliknya. Masalah-masalah yang dihadapi dari dynamic language khususnya di  JavaScript antara lain: * Uncaught TypeError: Cannot read property of undefined. * TypeError: 'null' is not an object. * TypeError: cannot read property 'length'. https://www.youtube.com/watch?v=EmBzyBQU760 [https://www.youtube.com/watch?v=EmBz

JavaScript adalah dynamic language yang singkatnya type dari suatu variable tersebut berdasarkan nilai nya. Yang artinya, tipe data pada variable mengikuti nilainya, bukan sebaliknya.

Masalah-masalah yang dihadapi dari dynamic language khususnya di  JavaScript antara lain:

  • Uncaught TypeError: Cannot read property of undefined.
  • TypeError: 'null' is not an object.
  • TypeError: cannot read property 'length'.
https://www.youtube.com/watch?v=EmBzyBQU760

Dan berbagai TypeError lainnya yang mana biasanya sumber masalahnya adalah "kesalahan jenis atau tipe data"

Mengapa bisa begitu? Diantaranya adalah:

  • Memberikan argumen ke function yang tidak sesuai dengan parameter yang diekspektasikan.
  • Perubahan nilai yang tidak dapat diprediksi saat runtime aplikasi yang dibuat dengan javascript.
  • Memanggil sebuah method yang tidak sesuai ekspektasi (memanggil properti length padahal tipe data saat runtime adalah sebuah object).

Masalah diatas dapat diselesaikan oleh bahasa pemrograman yang melakukan
"type checking" di compile time, runtime, and both compile and runtime karena setiap mendefinisikan sesuatu, misal seperti membuat function dibawah:

function x(lorem: string) string {
  return string
}

function x tersebut sudah didefinisikan parameter dan keluaran nilainya, yang mana bertipe data string.

Singkatnya, jika kita memanggil function x tidak sesuai dengan yang sudah didefinisikan, maka akan terjadi error, yang beruntungnya, type checker pada compiler akan memberitahu bahwa kode tersebut tidak dapat dijalankan karena memiliki masalah di type.

Dan keuntungan tersebut, hanya bisa didapatkan menggunakan bahasa pemrograman yang memiliki proses kompilasi. Di lingkungan web, bahasa pemrograman yang memiliki proses kompilasi yang paling populer adalah TypeScript, yang sebelumnya pernah dibahas disini.

Menjadi Programmer Web beneran dengan TypeScript
Maaf ya kalau judulnya menyebalkan, tapi aku serius kok. Dengan menggunakan TypeScript di project web kamu, secara tidak langsung kamu akan berurusan dengan Build tools, compiler, dan upacara-upacara lainnya yang ribet.

Selain TypeScript ada bahasa pemrograman lain yang menawarkan fitur "serupa" namun lebih menjanjikan yakni ReasonML.

Type System
|- Dynamic type `Runtime type checking`
|- Static Type checking `Compile type checking`
|- Combine or Both in runtime and compile.

Apa itu ReasonML?

ReasonML merupakan sebuah bahasa pemrograman yang dikembangkan oleh salah satu Engineer di Facebook yang bernama Jordan Walke, yang mana "Type System" dari ReasonML ini menggunakan OCaml (which is great) dan dibuat lebih familiar untuk JavaScript Engineer (which is nice).

Target platform dari bahasa pemrogrman ReasonML ini bervariasi, kita dapat menargetkan kode reason tersebut berjalan di berbagai environment
termasuk Native, Node.js, ataupun Web.

ReasonML
.
|
|-> OCaml -> Target Native -> Binary
|
|-> JavaScript -> use Bucklescript
                        | 
                        |
                        V
        plain JavaScript (default extension `.bs.js`).
                        |
                        |--> Target node.js
                        |--> Target Web platform aka browser.

Untuk project yang sudah menggunakan ReasonML, ada:

Dan untuk daftar lengkapnya bisa dilihat disini.

Yang maksudnya, ReasonML sudah teruji diberbagai skala bisnis (Jangan takut ke production bruh).

Key Concepts

  • A rock solid type system.
  • An eye for simplicity & pragmatism.
  • A focus on performance & size.  
  • Incremental learning & codebase conversion.  
  • Great ecosystem & tooling.  

Core Features

  • Function
  • Native, Byte Code, & Javascript
  • Binding & Scopes
  • Pattern Matching
  • Basic Modules
  • Variant Type
  • Polymorphic Variant Type
  • Lists & Arrays
  • Records
  • Functors
  • External & Internal iteration

Core Feature atau fitur inti dari bahasa ini termasuk kaya, dan tentunya membutuhkan learning curve yang tinggi. Dan, dalam tulisan ini tidak membahas secara keseluruhan untuk fitur inti tersebut. Namun, lebih pendeketan atau cara memulai (move on) ReasonML.

Overview

Sebagai contoh, misal kita membuat function untuk melakukan penambahan sederhana baik di JavaScript dan di ReasonML:

// Javascript
const add = (x,y) => x+y
add(3,5) // output: 8 
add(5,8) // output: 13


// ReasonML
let add = (x,y) => x+y // this is curry function by default

add(8,13)  // output: 21

8|>add(13) // output: 21

let wantAdd = add(13)

wantAdd(8) // output: 21
wantAdd(2) // output: 15

Terlihat familiar? Mungkin ada beberapa sintaks yang kurang familiar khususnya di bagian ReasonML, namun poinnya ada di pendefinisian function add yang sama - sama menggunakan gaya "arrow function".

Namun, di ReasonML, setiap function yang didefinisikan, "secara default" adalah "curry function". Kamu bisa lihat implementasi dari function add ada yang terlihat asing, bukan? Tepatnya pada wantAdd dan |> (Pipeline operator) yang nanti kita bahas untuk spesifik operator pada ReasonML.

Untuk Pipeline Operator akan ada juga loh di JavaScript (tapi masih proposal EcmaScript).

tc39/proposal-pipeline-operator
A proposal for adding the simple-but-useful pipeline operator to JavaScript. - tc39/proposal-pipeline-operator

Sekarang, mari kita lihat perbedaan yang lainnya:

// JavaScript
add('2', 2) // output: '22' -> String
add(-6,0.6) // output: '-5.4' -> Number  

// ReasonML
add('2', 2)
// Error: This expression has type char but an expression was expected of type

add(-6,0.6) 
// Error: This expression has type float but an expression was expected of type

See? Yang beruntungnya, error tersebut terjadinya di "compile time" bukan di "runtime", sehingga program kita akan aman berjalan di runtime, karena semua TypeError sudah diprediksi saat compile time.

ReasonML untuk JavaScript Developer

Berikut sedikit perbandingan antara "menulis" di JavaScript dan di Reason:

----------------------------------------------------------------------
| JavaScript                     | ReasonML
----------------------------------------------------------------------
| var x = 5                      | No equivalent (thankfully) 
| const x = 5                    | let x = 5 
| let x = 5                      | let x = ref(5) 
| "hello" + "world"              | "hello" ++ "world"
| "2" == 2                       | No equality with implicit casting (thankfully)
| function z(x,y){return x/y}    | let z = (x,y) => x/y;
----------------------------------------------------------------------
----------------------------------------------------------------------
|
| Lihat Selengkapnya:
| - https://reasonml.github.io/docs/en/syntax-cheatsheet
| - https://github.com/glennsl/bucklescript-ffi-cheatsheet
|
----------------------------------------------------------------------
----------------------------------------------------------------------
Syntax Cheatsheet · Reason
We’ve worked very hard to make Reason look like JS while preserving OCaml’s great semantics & types. Hope you enjoy it!
glennsl/bucklescript-ffi-cheatsheet
Contribute to glennsl/bucklescript-ffi-cheatsheet development by creating an account on GitHub.

Perlu diketahui bahwa setiap deklarasi "variable" di ReasonML itu "immutable by default".
Jadi, gimana bila kita ingin membuat variable yang mutable? Bisa menggunakan kata kunci ref saat deklarasi variable, contohnya:

let mutableInteger = ref(1);
let immutableInteger = 1;

mutableInteger := mutableInteger^ + 2; // output: 3

immutableInteger = immutableInteger + 2; 
// Error: The value immutableInteger is not an instance variable

REasonML untuk ReactJS Developer

Jika kamu adalah seorang Frontend Developer yang menggunakan React untuk membuat UI, Reason-pun memberikan kamu keluasan untuk mengunakan React dengan static type system, yakni via ReasonReact.

Berikut sedikit perbandingan dalam pembuatan komponen React di JavaScript dan ReasonML:

// JavaScript
// src/Button.js
const Button = ({children}) => <button>{children}</button>
const ButtonWithText = ({children}) => <Button>Click for HI!</Button>

// ReasonML
// src/Button.re
module Button = {
    [@react.component]
    let make = (~children) => <button>children</button>;
};

[@react.component]
let make = () => <Button>"Click for HI!"->React.string</Button>;

Bagaimana dengan hasil kompilasi, ReasonML ini untuk Browser/Web Environment?

// src/Button.bs.js
'use strict';

var React = require("react");

function Button$Button(Props) {
  var children = Props.children;
  return React.createElement("button", undefined, children);
}

var Button = {
  make: Button$Button
};

function Button$1(Props) {
  return React.createElement(Button$Button, {
              children: "Click for HI!"
            });
}

var make = Button$1;

exports.Button = Button;
exports.make = make;

Apa keuntungannya menggunakan React khususnya via ReasonML? Confidence, Type safety. Aplikasi terjamin keamanannya dari TypeError.

Mulai menggunakan Reason

Untuk mulai membuat aplikasi menggunakan ReasonML, kamu harus memasang beberapa tools seperti:

Yarn atau NPM digunakan untuk mengatur dependensi JavaScript dan bs-platform berguna untuk mengkompilasi kode Reason ke JavaScript alias untuk
target platform Web dan Node.js. Seharusnya kamu sudah memiliki npm atau yarn di mesin kamu, jika belum, silahkan pasang terlebih dahulu.

Sekarang, kita install bs-platform terlebih dahulu:

$ npm install -g bs-platform # yarn global add bs-platform

Jika sudah, kamu bisa verifikasi dengan menjalankan perintah berikut:

$ bsb -v

Jika muncul versi dari bs-platform tersebut, berarti sudah berhasil terpasang.

Sekarang, kita coba memulai untuk membuat project baru menggunakan Reason:

$ bsb -init <nama_project> -theme basic-reason
$ cd <nama_project>
$ tree -I node_modules
.
├── bsconfig.json
├── package.json
├── README.md
└── src
    └── Demo.re

1 directory, 4 files

Sumber kode berada di direktori src, dan untuk melihat daftar perintah yang tersedia, seperti biasa kamu bisa melihatnya di berkas package.json. Karena kita pakai bs-platform, berarti target kompilasi menjadi kode JavaScript. Sekarang mari kita coba bulid:

$ npm run build
why not use yarn

Hasil kompilasi akan berada di direktori src dengan ekstensi .bs.js. Mari kita buat fungsi sederhana untuk menampilkan kalimat sederhana:

// Greet.re
let greet = name => "hello " ++ name

Sekarang kita kompilasi:

$ npm run build

Jika kita lihat kode hasil kompilasinya (Greet.bs.js), isinya kurang lebih seperti ini:

// Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE
'use strict';


function greet(nama) {
  return "Hello " + nama;
}

exports.greet = greet;
/*  Not a pure module */

Tapi kita belum melakukan apa-apa, sekarang mari kita gunakan function tersebut:

let greet = name => "hello " ++ name

Js.log(greet("satan"))

Sekarang kita buid lagi, dan hasilnya kurang lebih akan menjadi seperti ini:

// Generated by BUCKLESCRIPT, PLEASE EDIT WITH CARE
'use strict';


function greet(nama) {
  return "Hello " + nama;
}

console.log("Hello satan");

exports.greet = greet;
/*  Not a pure module */

Js.log sama seperti console.log di JavaScript. Untuk sekarang terlihat belum ada "yang spesial" dari kode ini, mari kita coba buat spesial.

let greet = name => "hello " ++ name

Js.log(greet("satan"))
Js.log(greet(666))

Sekarang mari kita build:


$ npm run build

  We've found a bug for you!
  /home/r177/xxx/src/Greet.re 4:14-16

  2 │
  3 │ Js.log(greet("satan"));
  4 │ Js.log(greet(666));

  This has type:
    int
  But somewhere wanted:
    string

You can convert a int to a string with string_of_int.

Iya, benar sekali. Lihat bagaimana kode yang kita tulis gagal di build karena terdapat TypeError? Bahkan meskipun kita tidak "meng-eksplisitkan" tipe data dari parameter name, dikarenakan ReasonML memiliki "Inferrer", dia mengetahui parameter name merupakan string karena return nilai pada fungsi Greet adalah string check: "Hello" ++ name

Silahkan coba kalo di TypeScript dan lihat apa yang terjadi :))

Untuk membuat proses kompilasi berhasil, kita harus ubah int tadi ke string berdasarkan "saran" yang diberikan oleh compiler tersebut.

- Js.log(greet(666))
+ Js.log(greet(666->string_of_int)) // first-line operator
or
+ Js.log(greet(string_of_int(666)))
or
+ Js.log(greet("666"))

Jika sudah, dan kamu sudah memasang Node.js di mesinmu, mari kita coba jalankan kode js yang sudah dikompilasi oleh bsb-platform:

$ node src/Greet.re.js`

Hello satan
Hello 666

Jika kamu ingin bereksperimen lebih lanjut, kamu bisa gunakan tema lain (selain basic-reason) termasuk bila ingin mencoba menggunakan ReasonReact.

Untuk melihat list theme/template yang tersedia, kamu bisa jalankan perintah berikut:

$ bsb -themes
Available themes:
basic
basic-reason
generator
minimal
node
react-hooks
react-starter
tea 

Menarik?

Playground

untuk bermain dengan ReasonML kamu boleh memasang rtop, rtop merupakan CLI tool untuk menjalankan kode Reason dengan gaya REPL (Read Eval Print Loop) yang mana sudah dikemas didalam  paket reason-cli

Kuy, kita coba pasang :)

$ yarn add global [email protected]

kamu bisa ganti linux dengan sistem operasi yang kamu gunakan.

Atau jika kamu tidak suka memasang atau tidak suka dengan aplikasi CLI, kamu bisa mengunjungi tautan dibawah ini:

ReasonML Playground ~ https://reasonml.github.io/en/try.html
Sketch.sh ~ https://sketch.sh

Jika sudah terpasang, mari kita jalankan rtop yang nantinya akan muncul tampilan keren seperti ini:

Silahkan bermain-main bos!

Kekurangan & Kelebihan

Kekurangan:

  • Learning curve (Yah untuk core feature yang sangat banyak)
  • Ekosistem Di Indonesia (tidak se-laku toko sebelah)

Kelebihan:

  • Di "backing" dan didukung oleh perusahaan yang sangat besar (Facebook, Bloomberg, ahrefs)
  • Functional Programming (ML Family)
  • Easy to bind (interop/call existing JavaScript code)
  • Compiler yang insecure (A Rock Solid Type safe)
  • Module System (Struktur Project yang modular by default)
  • Mendukung Immutability dan Purity
  • Mendukung Cross-Platform
  • Banyak banget

Penutup

Kami di evilfactorylabs melihat peluang yang bagus untuk ReasonML agar bisa membuat aplikasi khususnya aplikasi web menjadi lebih aman (bugless), produktif dan fun. Tulisan ini adalah langkah awal kami dalam "mempopulerkan" dan membantu mengembangkan ekosistem ReasonML khususnya di Indonesia. Karena,

Jika suatu ekosistem teknologi itu minoritas, kenapa tidak untuk memulai menjadikannya mayoritas (Hidup Kaum Minoritas #MLFamiliy ~ Fun Fun Programming).

You in?

Jika kamu memiliki pertanyaan terkait Reason, kamu bisa bergabung di komunitas telegram ReasonML_ID atau bisa mention twitter @evilfactorylabs yang akan dibalas ekslusif oleh messiah Reason di evilfactorylabs.

ReasonML Indonesia
You can view and join @reasonML_id right away.
Tulisan ini hasil pair writing ~ powered by tmate.io (ri7nz & faultable) <3

Tulisan lain tentang ReasonML dalam Bahasa Indonesia

Perkenalan ReasonML, Sintaks Baru untuk OCaml - Personal site presented by Riza
ReasonML adalah bahasa sintaks, ekstensi dan toolchain yang berada diatas sebuah bahasa jadul OCaml. Selain dapat dikompilasi ke JavaScript dengan bantuan BuckleScript, Reason juga dapat dikompilasi menjadi aplikasi native melalui OCaml. Daripada membuat bahasa baru dari awal…
Mencicipi ReasonML untuk React
Menceritakan bagaimana rasanya mencicipi sintaksis ReasonML untuk membangun antarmuka sebuah website ReasonML, makanan apa ya? ReasonML…

Referensi

Menikmati tulisan ini?

Blog ini tidak menampilkan iklan, yang berarti blog ini didanai oleh pembaca seperti kamu. Gabung bersama yang telah membantu blog ini agar terus bisa mencakup tulisan yang lebih berkualitas dan bermanfaat!

Pendukung

Kamu?