bwdid-iterables



bwdid-iterables

0 2


bwdid-iterables

A presentation for DenverScript

On Github killtheliterate / bwdid-iterables

But What Does It Do... Iterables

Or: So you want to be a wizard.

Garrett Dawson

@killtheliterate

I've been a front-end dev of 5 years. I work at VictorOps

I love JavaScript

what are iterables, and what do you do with them?

Loops Are The Essence Of Programming

  • Loops are a fundamental
  • Without them... there is no program
  • You need loops and variables to be a programming language
* In order to talk about iterables, let's assert first principles * We take looping for granted, unless we're computer scientists

Extract the Patterns...

  • A list of things (counters, arrays, state)
  • A thing that steps through the list
So, if loops are programming, how do you loop? Identify the essence, recognize the similar props These decompose into Iterable/Iterator

Yup, Patterns

  // loopable
  const theIterable = [1,2,3]

  // the loop
  theIterable.forEach(el => console.log(el)) // 1, 2, 3

Given these commonalities, TC39 identifies Iterable/Iterator They capture the essence of looping into types

Thus Spoke TC39

Builtin Iterators

  • for-of
  • ...spread
  • {destructuring, assignment}
THESE ARE BUILT-INS let's talk about iteration with new stuff TC39 is the standards body Iterable/Iterator are part of JS now It's hard to talk about one without the other, but we'll begin with iterator

for-of

  // an iterable
  const theIterable = 'a string is a list of characters'

  // an iterator
  // access the member directly
  // instead of by index
  for(let char of theIterable) {
    console.log(char)
  }

Looks similar to for-in access member directly

...spread

  // an iterable
  const theIterable = ['an', 'array', 'is', 'iterable'] 

  // an iterator
  const newArray = [...theIterable]

  // arguments is iterable
  const fn = (...args) => { args.forEach(el => console.log(el)) }

  fn(1, 2, 3)

Looks alot like [].map() The arguments object can be passed to an iterator

{destructuring, assignment}

  // an iterable
  const theCollection = ['hello', 'humans', 'in', 'this', 'room']

  // an iterator
  let [these, are, pieces, ...iterable] = theCollection

  console.log(these) // 'hello'
  console.log(iterable) // ['this', 'room']

Also looks alot like [].map() Composable with ...spread to collect the rest Notably, objects can be destructured, but that's outside this scope

Thus Spoke TC39

Builtin Iterables

  • String
  • Array
  • Set
  • Map
  • Generators
Collection types All of these builtins describe how to traverse themselves That means they are consumable by any iterator Special case: Generators are both an Iterable and an Iterator

Strings

  // an iterable
  const theIterable = 'this is iterable'

  // an iterator
  for(let char of theIterable) {
    console.log(char) // each char
  }

  // an iterator
  const chars = [...theIterable]

  console.log(chars) // ['t','h','i','s',' '...]

Since they are iterable, they are consumable by iterators

Arrays

  // an iterable
  const theIterable = ['this', 'is', 'iterable']

  // an iterator
  for(let words of theIterable) {
    console.log(words) // 'this' 'is'...
  }

  // an iterator
  const sentence = [...theIterable]
  console.log(sentence) // ['this', 'is', 'iterable']

Sets

The Set object lets you store unique values of any type, whether primitive values or object references. Sets are very similar to arrays Like in math, Sets cannot have duplicate members The constructor accepts an iterable, and will make a Set with it

Sets

  // an iterable
  const theIterable = new Set()
  theIterable.add(1)
  theIterable.add(3)
  theIterable.add(2)
  theIterable.add(2)

  // an iterator
  for(let num of theIterable) {
    console.log(num) // 1, 3, 2
  }

  // an iterator
  const numbers = [...theIterable]
  console.log(numbers) // [1,3,2]

Maps

The Map object is a simple key/value map. Any value (both objects and primitive values) may be used as either a key or a value. Maps are like POJOs, but they guarantee order The constructor can take an iterable, and make a Map of it

Maps

  // an iterable
  const theIterable = new Map()
  theIterable.set('one', 1)
  theIterable.set('three', 3)
  theIterable.set('two', 2)

  // an iterator
  for(let numTuple of theIterable) {
    console.log(numTuple) // ['one', 1]...
  }

  // an iterator
  const tuples = [...theIterable]
  console.log(tuples) // [['one', 1]...]

Generators

Generators are functions which can be exited and later re-entered. Their context (variable bindings) will be saved across re-entrances. Both Iterable and Iterator You access next member using "next" This is what makes it an iterator, which should become clear later

Generators

  // an iterable
  const maker = function* () {
    yield 1
    yield 2
    yield 3
  }

  const theIterable = maker() // this gives us back a generator object
  const first = theIterable.next() // which we can step through
  console.log(first) // {value: 1, done: false}

yield keyword exits the function execution resumes where the yield left off

Generators

  // an iterable
  const maker = function* () {
    let index = 0 // the mutated state will be persisted

    while(index < 3) {
      yield index++
    }
  }

  const theIterable = maker() // this gives us back a generator object

  // which we can operate on with an iterator
  // this works because the generator is finite
  const nums = [...theIterable] // [0,1,2]

It's notable that using spread transforms the values into normal stuff

Generators

  // pushing a value with next() will become the result of the last
  // yield. like this:

  const maker = function* () {
    let first = yield
    let second = yield first
    let third = yield second
    yield
  }

  const echo = maker()

  console.log(echo.next(1))// {value: null, done: false}
  console.log(echo.next(500)) // {value: 500, done: false}
  console.log(echo.next('sup')) // {value: 'sup', done: false}

We can push values into Generators If we assign the last yield to a variable, that variable becomes whatever we push with next()

Protocol is the word

  • Or: an interface
  • Or: kind of a typeclass
abstract into a protocol The iterator protocol describes an interface I think it makes something part of a typeclass

Iterator Protocol

{ }.next()

An object is an iterator when it knows how to access items from a collection one at a time, while keeping track of its current position within that sequence "how do i loop?" this is why a generator is both iterable and iterator

Let's Make an Iterator

...for a linked list

http://bit.ly/1I8TKzc

  // this is what a linked list looks like
  {val: 1, rest: {val: 2, rest: {val: 3, rest: {val: 4, rest: null}}}}

  // basically an array
  [1, 2, 3, 4]

quick aside about linked lists why are they useful? memory and known size collection types in FP are usually linked lists you walk them recursively

Iterable Protocol

[Symbol.iterator]

The iterable protocol allows JavaScript objects to define or customize their iteration behavior, such as what values are looped over in a for..of construct. when you define a constructor, give it this property

Let's make an Iterable

...still a linked list

http://bit.ly/1T0WhvJ

  // give our type an iteration protocol
  const iterable = LinkedList()[Symbol.iterator] = () => // etc

we can make a linked list type that describes how it should be walked this makes our type "iterable"

Let's make an infinity

possible infinity

http://bit.ly/1PXumgX

* Event stream * Websockets * Observables * Combinators

Let's make applicatives

map, filter and reduce

  • Map: http://bit.ly/21ewFkR
  • Filter: http://bit.ly/1LxWRLZ
  • Reduce: http://bit.ly/1lHYuSo
* Thought it'd be fun to make applicatives for iterators and iterables * It may be ill-advised to work on both iterators and iterables

Question?

go broncos

But What Does It Do... Iterables Or: So you want to be a wizard. Garrett Dawson @killtheliterate I've been a front-end dev of 5 years. I work at VictorOps I love JavaScript what are iterables, and what do you do with them?