Composition

Photo by Yena Kwon on Unsplash

Composition

Original:

const creatureCanEat = creature => ({
    eat: food => `The ${creature} eats the ${food}.`
})

const creatureCanSleep = creature => ({
    sleep: () => `The ${creature} sleeps.`
})

const createCanEatSleep = creature => ({
    eat: food => `The ${creature} eats the ${food}.`,
    sleep: () => `The ${creature} sleeps.`
})

Example: Composition

const creatureCanEat = creature => ({
    eat: food => `The ${creature.name} eats the ${food}.`
})

const creatureCanSleep = creature => ({
    sleep: () => `The ${creature.name} sleeps.`
})

const creature = name => (state = { name }) => ({
    ...state,
    ...creatureCanEat(state),
    ...creatureCanSleep(state)
})

const cat = creature("cat");
cat.eat("salmon") // The cat eats the salmon.
cat.sleep() // The cat sleeps.

Potential problems: Changing state equates to object generation.

State in Closure

Counter

const counterFn = (counter = 0) => () => ++counter

const incrementer = counterFn();
incrementer(); // 1
incrementer(); // 2
incrementer(); // 3

const timerFn = (timer = 60) => () => --timer

const minute = timerFn();
minute(); // 59
minute(); // 58

const ten = timerFn(10);
ten(); // 9
ten(); // 8

Create an App State

const storeState = (currentState = {}) 
=> (stateChangeFunction = state => state)  
=> {
    const newState = stateChangeFunction(currentState);
    currentState = { ...newState };
    return newState;
}
const stateControl = storeState();

const stateChange = (prop) => (value) => (state) => ({
    ...state,
    [prop]: (state[prop] || 0) + value
})

Uses of state

const distance = stateChange("distance");
const throwFar = distance(100);
const speed = stateChange("speed");
const throwFast = speed(200);

const robot = stateControl();
const robot_modified_1 = distance(10)(robot);
const robot_modified_2 = throwFast(robot_modified_1);
// robot { distance: 10, speed: 200 }
const robot_2 = stateControl(throwFar);
const robot_2_modified = speed(20)(robot_2);
// robot { distance: 100, speed: 20 }
const robot_3 = storeState(robot_modified_2)(throwFar);
// robot { distance: 110, speed: 200 }

Despite aiming for reusability stateChange, storeState and so stateControl are limited in making one change at a time, generating a new object for each change or addition in state. To create particular arrangements will end up in composing numerous templates, which is no less unruly than numerous object classes. Each line of code is also part of memory.

Also, since each change or addition in state is the generation of a new object, once managing millions of instances of objects and objects with numerous properties (or states), it's unsustainable and can't be used for massive data sets.

Feasible to a magnitude of 6: full array operations with map up to seconds

Test for Self

Magnitudes: 3 - 7
Array per "user": stateless objects (users: magnitudes 3 - 6)
Perform operations on user arrays
- update every object
- locate, insert, delete, and update

Lookup answer: How do you test latency and load bearing?

Practice Problems

Painter paints

const painter1.paints() // "Paints green!"
const painter2.paints() // "Paints yellow!"
const painter3.paints() // "Paints red!"

Function: paint()

const paint = (color) => () => `Paints ${color}!`

const painter1 = ({ paints: paint("green") })
const painter2 = ({ paints: paint("yellow") })
const painter3 = ({ paints: paint("red") })

Object sound

faucet.sound() // "Drip drip drip"
oldCar.sound() // "Grumble grumble"
sleepyBear.sound() // "Grrr...ywn"

Function: sound()

const sound = (sound) => () => sound

const faucet = ({ sound: sound("Drip drip drip") })
const oldCar = ({ sound: sound("Grumble grumble") })
const sleepyBear = ({ sound: sound("Grr...yawn") })

Battle Robots

battleRobot1.throw()
// "The battle robot throws the spear 100 years at 200 miles per hour!"

Function: throw()

const throw = (distance) => (speed) => () => `The battle robot throws the spear ${distance} yards at ${speed} miles per hour!`
const battleRobot = (distance, speed) => ({
    throw: throw(distance)(speed)
})

Dancer dances

dancer.samba() // "The dancer sambas!"
dancer.tango() // "The dancer tangos!"

Functions: [dance]()

const dance = (subject) => (name) => () => `The ${subject} ${name}s!`
const addDance = dance("dancer")
const dancer = {
    samba: addDance("samba"),
    tango: addDance("tango"),
    dab: addDance("dab")
}