Functional JS

JaxNode July 2017

Upcomming events

  • Jax Tech Meetup on August 11th
  • CodeImpact in August 26th

Sponsors

  • Availity
  • Interactive Resources
  • Swyft Technology

JaxNode is looking

for Speakers!!!

  • Electron
  • Go Lang
  • Kubernetes, Swarm or Mesos
  • Client Side frameworks
  • WebAssembly/WASM
  • NAPI
  • Any other JavaScript topic
  • JavaScript History
  • Pure Functions
  • Closures
  • Classes vs Object Literals
  • Currying
  • Higher Order Functions
  • Functors
  • Monads
  • Promises
  • Async/Await
  • Immutability
  • Bind and Pipe Operator proposals

Topics

Douglas Crockford

"JavaScript is the only programming language that people try to program in before actually learning the language"

Brendan Eich

Hired by Netscape

Wanted to do Scheme

Had to look like Java

We got JavaScript

Functional Programming

  • Is a programming paradigm
  • Declarative over Imperative
  • Avoid changing state and mutability
  • Create structures of elements
  • Uses functions for computational change
  • Try to use Pure Functions
  • Avoid Side-effects

Why learn functional programming?

  • Because it is AWESOME!
  • Many JS frameworks like React and Redux based on functional programming concepts
  • Helps you write code with less errors
  • Generally results in less code 

Functional Langages

  • Lisp
  • Haskell
  • Erlang
  • F#
  • Scala
  • Elixir
  • Elm

Is Javascript functional?

  • Functions are first class citizens
  • Closures allow inner functions to access parents scope
  • Functions can be passed as parameters
  • Functions can be returned from functions
  • Global scope can be problemattic

pure functions

function add(a, b) {
    return a + b;
}

const c1 = add(12, 14); // 26
const c2 = add(100, -1); // 99
const c3 = add(34, 17); // 51

non-pure functions

let state = 0;

function addToState(value) {
    state += value;
    return state;
}

let c1 = addToState(3); // 3
let c2 = addToState(10); // 13
let c3 = addToState(3); // 16

closures

const counter = function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  };   
};

const myCounter = counter();
myCounter.increment(); // Changes privateCounter to 1
myCounter.value(); // returns 1

Es6/2015 and other Controversies

  • 'class' and 'super' keyword
  • 'new' keyword
  • Functional programmers should try to avoid these

C# Class

// C#
public class Animal {
    public string Name { get; set; }
    public int Limbs { get; set; }

    public Animal(name, limbs) {
        this.Name = name;
        this.Limbs = limbs;
    }

    public void printAnimal() {
        if (this.Limbs == 0) {
            Console.PrintLine(@"You have a " + 
                this.Name + " with no limbs.");
        } else if (this.Limbs == 1) {
            Console.PrintLine(@"You have a " + 
                this.Name + " with " + 
                this.Limbs.ToString() + " limb.");
        } else {
            Console.PrintLine(@"You have a " + 
                this.Name + " with " + 
                this.Limbs.ToString() + " limbs.");
        }
    }
}

ES6/2015 class

class Animal {
    constructor(name, limbs) {
        this.Name = name;
        this.Limbs = limbs;
    }

    printAnimal() {
        if (this.Limbs === 0) {
            console.log(`You have a ${this.Name} with no limbs.`);
        } else if (this.Limbs === 1) {
            console.log(`You have a ${this.Name} with ${this.Limbs} limb.`);
        } else {
            console.log(`You have a ${this.Name} with ${this.Limbs} limbs.`);
        }
    }
}

es6 class invocation

const Cat = new Animal('Gato', 4);
const Dog = new Animal('Perro', 3);

Cat.printAnimal(); // You have a Gato with 4 limbs.
Dog.printAnimal(); // You have a Perro with 3 limbs.

$('#myButton').on('click', Cat.printAnimal()); // Doesn't work

$('#myButton').on('click', Cat.printAnimal.bind(this)); // Will work

$('#myButton').on('click', _ => Cat.printAnimal()); // Will work

Object literal classes

const MakeAnimal = (name, limbs) => {
    const Name = name;
    const Limbs = limbs;
    return {
        printAnimal: () => {
            if (Limbs === 0) {
                console.log(`You have a ${Name} with no limbs.`);
            } else if (Limbs === 1) {
                console.log(`You have a ${Name} with ${Limbs} limb.`);
            } else {
                console.log(`You have a ${Name} with ${Limbs} limbs.`);
            }    
        }    
    }
};

Alternatives to new and super

  • Douglas Crockford proposed Object.create()
  • Avoids having constructors
  • Object.create(proto[, propertiesObject])
  • by default properties ARE NOT writable,
    enumerable or configurable
const person = {
  sayName: function () { 
    console.log(`my name is ${this.myName}`) 
  }
}

const bar = Object.create(person);
bar.myName = 'Dinesh';
bar.sayName(); // my name is Dinesh
// This property is overwritable
bar.myName = 'Gilfoyle';
bar.sayName(); // my name is Gilfoyle
const baz = Object.create(person, 
  { myName: { 
    get: function() { return 'Erlich'; } 
  } 
});

baz.sayName(); // my name is Erlich
baz.myName = 'Richard'; // Will throw error! This property is not overwritable.

Object composition over inheritance

  • Object.assign() to create new object from multiple objects and properties
  • Helps avoid the Gorilla Banana problem with classical inheritance chains
  • Used with Redux and React for transforming state 

const sounder = (state) => ({
    makeSound: () => console.log(state.sound)
});

const namer = (state) => ({
    sayName: () => console.log(`My name is ${state.name}.`)
})

const state = { 
    name: 'Bill',
    sound: 'Ack Ack!'
};

const cat = Object.assign({}, sounder(state), namer(state));

cat.makeSound(); // Ack Ack!
cat.sayName(); // My name is Bill.

Currying

  • Currying allows for partial application of function calls
  • Syntax can look like: myFunction('Red')('Blue')
  • Functions can return other functions or themselves

Currying

const greeter = function(greeting) {
    return function(name) {
        console.log(`${greeting} there ${name}!`);
    }
};

const greet = greeter('Hi');
greet('David'); // Hi there David!
greet('Andy'); // Hi there Andy!
// or

greeter('Hi')('Frank'); // Hi there Frank!

Higher order functions

  • higher order functions accept functions as parameters
  • filter, map and reduce all considered higher order
  • => operator can be used for short form
  • Declarative over Imperative example

Imperative filter

function filterGT2(arr) {
  let newArray = [];
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] > 2) {
      newArray.push(arr[i]);  
    }
  }
  return newArray;
} 

console.log(filterGT2([-1, 0, 1, 2, 4, 5, 7]));
// returns [4, 5, 7];

higher order filter

console.log([-1, 0, 1, 2, 4, 5, 7].filter(i => i > 2));
// returns [4, 5, 7]

MAP

const multipleBy2 = (item) => item * 2;

[3, 4, 8, 5].map(multipleBy2); // returns [6, 8, 16, 10]

Reduce

const arr = [ 6, 8, 16, 10 ];
const sum = arr.reduce((a, i) => a += i, 0); // returns 40

Functors

  • Implements Map
  • Holds a set of values
  • Map returns a Functor of the same size
  • Array object is an example of a Functor
  • filter, map and reduce all can return Functors

Douglas Crockford

Once someone learns what a Monad is, it becomes physically impossible for them to describe what a Monad is to someone else.

Crockford on Monads

Monads

  • Monads are a type of Functor
  • Monads generally implement some form of FlatMap
  • Allow developers to manage side effects
  • Promises are a form of Monad
  • JQuery object is also a Monad
  • Highland JS library also a Monad

Promises

  • Easier implementation for handling asynchronous callbacks
  • Original pattern in JS was the error first callback
  • fs.open('myfile', 'wx', (err, fd) => { ... })
  • Could be implemented with a Promise like this;
  • fs.open('myfile').then(d => { ... }).catch(err => log(err))
  • async and await keywords use promises

Error first callback

const fs = require('fs');

fs.stat('.', function cb(err, result) {
    if (err) {
        console.error(err);
    }
    console.log(result);
});

Promise

fetch('https://www.jaxnode.com/v1/api/meeting')
    .then(response => {
        return response.json();
    })
    .then(json => {
        console.log(json);
    })
    .catch(err => {
        console.error(err);
    });

Defining a promise

// Copyright Mozilla.org
function myAsyncFunction(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url);
    xhr.onload = () => resolve(xhr.responseText);
    xhr.onerror = () => reject(xhr.statusText);
    xhr.send();
  });
});

Node 8 util.promisfy

const util = require('util');
const fs = require('fs');

const stat = util.promisify(fs.stat);

stat('.')
    .then((stats) => {
      console.log(stats);
    })
    .catch((error) => {
      console.error(error);
    });

promises with async await

const util = require('util');
const fs = require('fs');

const stat = util.promisify(fs.stat);

async function callStat() {
  const stats = await stat('.');
  console.log(`This directory is owned by ${stats.uid}`);
}

"50% of the bugs that people run into today, coding with C# in our platform, and the same is true of Java for that matter, are probably null reference exceptions. If we had had a stronger type system that would allow you to say that ‘this parameter may never be null, and you compiler please check that at every call, by doing static analysis of the code’. Then we could have stamped out classes of bugs."

Anders Hejlsberg

IMMUTABLE JS

  • JS library to prevent user from changing variables
  • Has set of types for Map, List, Range and others.
  • Avoid null!!!
  • State is the source of many errors, and is the root of all EVIL!
  • ES6/2015 introduced 'const' and 'let' keywords
  • Try to use 'const' and 'let' keywords over 'var'
  • Mori is a library based on Closure script that does many of the same things as Immutable JS

Bind & Pipe Operator

  • ES Proposal for Bind and Pipe operators
  • Bind operator would use ::
  • Pipe operator would use |>
// Copyright 2017 Michael K. Snead
// https://medium.com/@aikeru/can-we-please-promote-the-bind-operator-939845ca6ae5

function pipeline(fn, ...args) {
  return fn && fn(this, ...args)
}

//Used like so
const addAll = (...numbers) => numbers.reduce((a, b) => a + b);
5 :: pipeline(addAll, 2);
// copyright 2016 https://github.com/gilbert/es-pipeline-operator
function doubleSay (str) {
  return str + ", " + str;
}
function capitalize (str) {
  return str[0].toUpperCase() + str.substring(1);
}
function exclaim (str) {
  return str + '!';
}

let result = exclaim(capitalize(doubleSay("hello")));
console.log(result); //=> "Hello, hello!"
let result2 = "hello"
  |> doubleSay
  |> capitalize
  |> exclaim;

console.log(result2); //=> "Hello, hello!"
result2
  |> console.log; // => "Hello hello!"

Questions ?

resources

Functional JavaScript

By David Fekke

Functional JavaScript

These are the slides for the Functional JavaScript presentation for JaxNode

  • 1,551