Slide 1

Slide 1 text

@MoOx C'est qui Reason(ML) et qu'est ce qu'il fait là? 1

Slide 2

Slide 2 text

@MoOx Do you need redux? 2 Previously in React Toulouse…

Slide 3

Slide 3 text

@MoOx Redux
 is a predictable state container for JavaScript apps. 3 Previously in React Toulouse…

Slide 4

Slide 4 text

@MoOx What redux does, ReasonReact and Elm do 4 Actions are types, reducers are functions,
 state is immutable, but at the language level Previously in React Toulouse…

Slide 5

Slide 5 text

@MoOx “done in collaboration with the ReactJS team” 5 https://reasonml.github.io/reason-react/blog/2017/09/01/reducers.html Previously in React Toulouse…

Slide 6

Slide 6 text

@MoOx 6 JS

Slide 7

Slide 7 text

@MoOx • Available everywhere • Easy to start • Multiparadigm 7

Slide 8

Slide 8 text

@MoOx • Super hard to master • Error prone • Hacky 8

Slide 9

Slide 9 text

@MoOx 9 let add = (a, b) => a + b;

Slide 10

Slide 10 text

@MoOx 10 add(1, 1); // 2 add(1, "1"); // "11" add(1, null); // 1 add(1, undefined); // NaN

Slide 11

Slide 11 text

@MoOx Dynamic typing + Automatic coercion 11

Slide 12

Slide 12 text

@MoOx 12

Slide 13

Slide 13 text

@MoOx 13

Slide 14

Slide 14 text

@MoOx • ESLint? • Flow? • TypeScript? 14

Slide 15

Slide 15 text

@MoOx 15

Slide 16

Slide 16 text

@MoOx Developers are humans 16 And we make mistakes

Slide 17

Slide 17 text

@MoOx What about TESTS? 17

Slide 18

Slide 18 text

@MoOx We covers what we think about. 18 And we are developers. And we make mistakes

Slide 19

Slide 19 text

@MoOx 19

Slide 20

Slide 20 text

@MoOx 20

Slide 21

Slide 21 text

@MoOx 21 1. A language 2. A syntax 3. A compiler 4. An ecosystem

Slide 22

Slide 22 text

@MoOx OCaml 22 %

Slide 23

Slide 23 text

@MoOx • Has a great type system • Infers most types • Multiparadigm 23

Slide 24

Slide 24 text

@MoOx Syntax can be hard Tooling can be hard 24

Slide 25

Slide 25 text

@MoOx let rec map f = function [] -> [] | a::l -> let r = f a in r :: map f l 25

Slide 26

Slide 26 text

@MoOx 1. A language 2. A syntax 3. A compiler 4. An ecosystem 26

Slide 27

Slide 27 text

@MoOx ~ES2015+ 27 JS

Slide 28

Slide 28 text

@MoOx 28 let add a b = a + b let add = (a, b) => a + b; ML RE

Slide 29

Slide 29 text

@MoOx 29 1. A language 2. A syntax 3. A compiler 4. An ecosystem

Slide 30

Slide 30 text

@MoOx BuckleScript 30

Slide 31

Slide 31 text

@MoOx RE 31 JS

Slide 32

Slide 32 text

@MoOx • Outputs clean and performant code • Makes interop easy 32 BUCKLESCRIPT

Slide 33

Slide 33 text

@MoOx 33 1. A language 2. A syntax 3. A compiler 4. An ecosystem

Slide 34

Slide 34 text

@MoOx 34 npm

Slide 35

Slide 35 text

@MoOx A bit of practice? 35

Slide 36

Slide 36 text

@MoOx 1. Basics 2. Modules 3. Functions 4. Variants 5. Interop 36

Slide 37

Slide 37 text

@MoOx 37 BASICS 1; /* int */ 1.0; /* float */ "Hello"; /* string */ 'H'; /* char */ true; /* bool */

Slide 38

Slide 38 text

@MoOx 38 BASICS [1, 2, 3]; /* list(int) */ [|1, 2, 3|]; /* array(int) */ Some(x); /* option('a) */ () /* unit */

Slide 39

Slide 39 text

@MoOx 39 RECORDS let me = { name: "Matthias", age: 24, }; let meLater = { ...me, age: 25, }; type user = { name: string, age: int, }; You declare the type of the record You can create records of this type You can create spread values to create a new record from a previous one

Slide 40

Slide 40 text

@MoOx 1. Basics 2. Modules 3. Functions 4. Variants 5. Interop 40

Slide 41

Slide 41 text

@MoOx 41 App.re MODULES Every file is a module and filenames are unique Welcome.re let sayHi = (name) => Js.log("Hi " ++ name ++ "!"); Welcome.sayHi("people"); Every top level binding is exported by default To open a module, just use its capitalised name

Slide 42

Slide 42 text

@MoOx 42 MODULES module Talk { include Presentation; let slides = ["a", "b", "c"]; let slidesWithIndex = slides ->Belt.List.mapWithIndex((index, item) => (index, item)); }; open OtherModule; Declare a module within a module Include modules like a static extends Make all module available in scope

Slide 43

Slide 43 text

@MoOx 1. Basics 2. Modules 3. Functions 4. Variants 5. Interop 43

Slide 44

Slide 44 text

@MoOx 44 FUNCTIONS let add = (a, b) => a + b; let addDoubles = (a, b) => { let doubleA = a * 2; let doubleB = b * 2; doubleA + doubleB; }; Every function has its signature let add: (int, int) => int = ; Last expression is the returned value

Slide 45

Slide 45 text

@MoOx 45 FUNCTIONS Pipe operator! Functions are auto curried That means that they return a function taking the rest of the arguments as long as you didn't pass all the required ones [1, 2, 3] ->Belt.List.keep(item => item mod 2 === 0) ->Belt.List.map(item => item * 2);

Slide 46

Slide 46 text

@MoOx 46 FUNCTIONS let make = ( ~rootPath="./", ~fileExtensions=["re", "js"], ~watch=false, ~onChange=?, () ) => { /* ... */ }; Functions can have labelled arguments Their order at function application doesn't mater Optionals Default values Final non labelled argument When you have optional arguments, this tells the compiler «I have all the arguments there»

Slide 47

Slide 47 text

@MoOx 1. Basics 2. Modules 3. Functions 4. Variants 5. Interop 47

Slide 48

Slide 48 text

@MoOx 48 WHAT'S WRONG WITH THIS? type state = { isLoading: false, hasErrored: false, data: null, };

Slide 49

Slide 49 text

@MoOx 49 IMPOSSIBLE STATES ARE ACTUALLY POSSIBLE isLoading hasErrored data FALSE FALSE NULL TRUE FALSE NULL FALSE TRUE NULL TRUE TRUE NULL FALSE FALSE DATA TRUE FALSE DATA FALSE TRUE DATA TRUE TRUE DATA NotAsked Loading Errored Loaded

Slide 50

Slide 50 text

@MoOx 50 THE SOLUTION: VARIANTS type t('a) = | NotAsked | Loading | Loaded('a) | Errored; A variant type is a «OR» type A type can be parametrised aka Generics Every constructor can hold data like a container type

Slide 51

Slide 51 text

@MoOx 51 THE SOLUTION: VARIANTS switch (resource) { | NotAsked => "" | Loading => "Loading ..." | Loaded(value) => "Loaded: " ++ value | Errored => "An error occurred" }; You use pattern matching to extract values

Slide 52

Slide 52 text

@MoOx 52 THE SOLUTION: VARIANTS switch (resource) { | NotAsked => "" | Loading => "Loading ..." | Loaded(value) => "Loaded: " ++ value }; Warning 8: this pattern-matching is not exhaustive. Here is an example of a value that is not matched: Errored

Slide 53

Slide 53 text

@MoOx 53 THERE'S NO NULL type option('a) = | Some('a) | None; switch (value) { | Some(value) => value | None => "Nothing to see" }; Move null checks at compile time If it's maybe a value, you need to handle it explicitly

Slide 54

Slide 54 text

@MoOx 54 1 ARRAY VS LIST 1 2 3 1 1 1 2 1 3 1

Slide 55

Slide 55 text

@MoOx 55 LIST IS A VARIANT TYPE type list('a) = | Empty | Head('a, list('a)); let list = Head(1, Head(2, Head(3, Empty)));

Slide 56

Slide 56 text

@MoOx 56 LIST IS A VARIANT TYPE If there's nothing left Return empty Return a head with transformed item then transform the rest with a recursive call Recursive let rec map = (f, list) => switch (list) { | Empty => Empty | Head(x, rest) => Head(f(x), map(f, rest)) };

Slide 57

Slide 57 text

@MoOx 57 LIST IS A VARIANT TYPE Reassigned Reassigned let foldLeft = (array, f, acc) => { let index = -1; while(++index < array.length) { acc = f(acc, array[index]) }; return acc };

Slide 58

Slide 58 text

@MoOx 58 ACTUALLY IN JS // http://es5.github.io/#x15.4.4.21 function foldLeft(arr, fn) { var array = new Object(arr), index = -1, length = array.length >>> 0, acc, hasInitialValue; if (Object.prototype.toString.call(fn) != "[object Function]") { throw new TypeError(); } if (arguments.length > 1) { acc = arguments[1]; } else { hasInitialValue = false; while (++index < length) { if (!(hasInitialValue = index in array)) { continue; } acc = array[index]; break; } if (!hasInitialValue) { throw new TypeError(); } } while (++index < length) { if (!(index in array)) continue; acc = fn.call(void 0, acc, array[index], index, array); } return acc; };

Slide 59

Slide 59 text

@MoOx 59 ACTUALLY IN JS: DYNAMIC TYPING // http://es5.github.io/#x15.4.4.21 function foldLeft(arr, fn) { var array = new Object(arr), index = -1, length = array.length >>> 0, acc, hasInitialValue; if (Object.prototype.toString.call(fn) != "[object Function]") { throw new TypeError(); } if (arguments.length > 1) { acc = arguments[1]; } else { hasInitialValue = false; while (++index < length) { if (!(hasInitialValue = index in array)) { continue; } acc = array[index]; break; } if (!hasInitialValue) { throw new TypeError(); } } while (++index < length) { if (!(index in array)) continue; acc = fn.call(void 0, acc, array[index], index, array); } return acc; };

Slide 60

Slide 60 text

@MoOx 60 LIST IS A VARIANT TYPE let rec fold_left = (f, acc, list) => switch (list) { | [] => acc | [x, ...rest] => fold_left(f, f(acc, x), rest) };

Slide 61

Slide 61 text

@MoOx 1. Basics 2. Modules 3. Functions 4. Variants 5. Interop 61

Slide 62

Slide 62 text

@MoOx How do we incrementally adopt Reason on an existing codebase? 62 INTEROP

Slide 63

Slide 63 text

@MoOx 63 INTEROP: EXTERNAL MODULES [@bs.module "../myExistingJsModule"] external myExistingJsModule : string = ""; Declare that it's a module located at "../myExistingModule" The module is of string type Js.log(myExistingJsModule); The module is only imported when used

Slide 64

Slide 64 text

@MoOx 64 INTEROP: EXTERNAL MODULES // Generated by BUCKLESCRIPT VERSION 2.2.4, PLEASE EDIT WITH CARE 'use strict'; var MyExistingJsModule = require("../myExistingJsModule"); console.log(MyExistingJsModule.myExistingJsModule); /* Not a pure module */

Slide 65

Slide 65 text

@MoOx 65 INTEROP: CREATE AND READ JAVASCRIPT OBJECTS let myJsObject = { "name": "Matthias", "age": Js.Null.return(24) }; Js.log(myJsObject##name);

Slide 66

Slide 66 text

@MoOx 66 INTEROP: ACCESS THE JS STDLIB array |> Js.Array.map(item => item * 2);

Slide 67

Slide 67 text

@MoOx ReasonReact 67

Slide 68

Slide 68 text

@MoOx 68

Slide 69

Slide 69 text

@MoOx 69 WHERE DOES REACT COME FROM? • Immutability • Functional approach • PropTypes

Slide 70

Slide 70 text

@MoOx 70 WHERE DOES REACT COME FROM? Creator of React Jordan Walke wrote the first React prototype in SML

Slide 71

Slide 71 text

@MoOx 71 REASONREACT HAS A LOT BAKED IN • Components • Router • Reducers • Subscriptions

Slide 72

Slide 72 text

@MoOx 72 JSX

Slide 73

Slide 73 text

@MoOx 73 REASONREACT: BASIC COMPONENT let component = ReasonReact.statelessComponent("HelloWorld"); let make = (~name, _children) => { ...component, render: (_self) =>
(ReasonReact.string("Hello " ++ name))
};

Slide 74

Slide 74 text

@MoOx 74 REASONREACT: REDUCER COMPONENT Define the type of the state Define all possible actions type state = int; type action = | Increment | Decrement; let component = ReasonReact.reducerComponent("Counter");

Slide 75

Slide 75 text

@MoOx 75 REASONREACT: REDUCER COMPONENT Return an update for each action can be Update, UpdateWithSideEffect, SideEffect … reducer: (action, state) => switch (action) { | Increment => ReasonReact.Update(state + 1) | Decrement => ReasonReact.Update(state - 1) }

Slide 76

Slide 76 text

@MoOx 76 REASONREACT: REDUCER COMPONENT Send actions in your render function render: ({state, send}) =>
(ReasonReact.stringToElement(string_of_int(state))) send(Increment)) title="+" /> send(Decrement)) title="-" />

Slide 77

Slide 77 text

@MoOx 77 REASONREACT: INTEROP ReasonReact.wrapReasonForJs(/* ... */) ReasonReact.wrapJsForReason(/* ... */)

Slide 78

Slide 78 text

@MoOx Sum up 78

Slide 79

Slide 79 text

@MoOx • Safer • Less bugs • Easy refactoring 79 SUM UP

Slide 80

Slide 80 text

@MoOx We all come up with the wrong assumptions on our first pass at something 80 SUM UP

Slide 81

Slide 81 text

@MoOx Fix your assumptions at the type level and let the compiler show you the way 81 SUM UP

Slide 82

Slide 82 text

@MoOx Spaghetti Reason code is better than spaghetti JS 82 SUM UP

Slide 83

Slide 83 text

@MoOx C’est une bonne raison pour utiliser Reason 83 SUM UP: ONE QUESTION

Slide 84

Slide 84 text

@MoOx 84 Questions ? https://moox.io/ @MoOx Maxime Thirouin Matthias Le Brun @bloodyowl Slides ripped from