Monads, Promises,

and

Reactive Metaprogramming!

May 15 2014, Verona

Massimiliano Mantione

(Hyperfair CTO)

Stop the buzzwords

Honestly, I fear will not see
a lot of new things in this talk

However, I hope to inspire you new ideas
on how code can be written

Who fears
callback hell?

This talk is mostly about async programming

(the other half is about metaprogramming)

We all know async is hard in "pure" Javascript

Do we?

Let's see...

Think differently

The easiest way make an API asynchronous
is to get a callback as argument

But this matters nothing!

We think that the problem is the nesting of callbacks...

But it is the nesting of callbacks!

Nesting

Did you know...

That also synchronous code can suffer from nesting?

writeFiles(
  resizeImages(
    readFiles(
      listFiles(directoryName))));
      

The root of the problem

Nested expressions are unreadable

A nested expression is a complex one

A complex expression is a deep tree

Usually what we want is a single path in the tree!

Be pragmatic

Parenthesis must be nested

Representing tree levels with parenthesis produces nesting

A single tree path is like a linked chain

Binary, left-associative infix operators can be chained

The "." operator links very versatile entities
(objects and properties)

Let's think...

Remember: the "." operator links very versatile entities
(objects and properties)

Let's build objects that represent the steps in the chain!

Every object will have a method that returns the next step in the chain...

Enter the

Flowing API!

listFiles(directoryName)
  .readFiles()
  .resizeImages()
  .writeFiles();

This usually works well, but...

Is there a

simpler

way?

Expression

Trees!

Let's see how the language
can help us
"straightening" trees

Sounds scary?

It is: write the wrong macro and your code will become an unreadable mess

With great power comes great responsibility

Macros give you superpowers

Would you really give up superpowers
because you don't want the responsibility?

Let's revisit callback hell

Monads

Monadic sequencing

Does anybody understand monads?

No?

Neither do I!

Please watch the talk
"Monads and Gonads"
by Douglas Crockford

Monads for dummies

Suppose you want to compute result r from value v applying functions f1, f2 and f3

r = f3 (f2 (f1 (v)));

(note the nesting)

You could represent the intermediate values explicitly:
v1 and v2

v1 = f1 (v);
v2 = f2 (v1);
r  = f3 (v2);

(note: no nesting!)

But lots of clutter...

Monads for dummies

You could build a flowing API...

r = v.f1().f2().f3();

...or you could have a "monadic sequencing" notation:

r = on v do
  f1
  f2
  f3

(note: this is not Javascript)

Monads for dummies

Monads are objecs that encapsulate a function

Actually, they represent the (future?) result of applying that function

They can be linked to other monads, which represent the input and result of the function...

Does this ring a bell?

Promises!

Go async with promises

Remember that each step in the chain represents an intermediate value

listFiles(directoryName)
  .then(readFiles)
  .then(resizeImages)
  .then(writeFiles);
  

What about failure?

Let's add something to our previous example

listFiles(directoryName)
  .then(readFiles)
  .then(resizeImages)
  .then(writeFiles)
  .fail(handleError)

What does the final fail invocation add?

The expression is a list,
but what about the flow of values?

Nonlinear graphs!

This is the graph of intermediate values:

// directoryName --------\
//       |               |
// listFiles ------------+
//       |               |
// readFiles ------------+
//       |               |
// resizeImages ---------+
//       |               |
// writeFiles        handleError

As you can see, this is not a simple chain of values!

However, it can be represented as a list
because of a "try-catch" trick

What about

Rx.Js?

An observable can do one of three things:

  • Produce values: onNext
  • Terminate: onCompleted
  • Fail: onError

The rx.js graph

// observable -----+----------\
//     |           |          |
//   filter -------+----------+
//     |           |          |
//  throttle ------+----------+
//     |           |          |
//    map ---------+----------+
//     |           |          |
//   onNext   onCompleted  onError

Like a monad, with three functions...

Rx.Js is different

It adds some real value over promises

Promises frameworks lack the comprehensive set of operations on flowing values that Rx.Js has

Moreover, promises can fire only once, while observables are more like node.js streams

Of course, ES6 and ES7 will support Promises and not Rx.Js

Let's look at some code!

Final thoughts

The problem is the nesting and not the callbacks

(a verbose syntax is annoying anyway)

Promises give you linear code, but they require a global API conversion

A smarter language can give you linear code with any API
(Promises, Rx.Js, or plain callbacks)

Other techniques

Rx.Js adds real value, but will it ever be supported by Javascript?
(think async in ES7)

Don't forget generators and coroutines!

But... when will we have
migratable coroutines?

That's All, Folks

Metascript

is waiting for you!

code, docs and slides are on github

twitter: @M_a_s_s_i, #metascript

group: metascript@googlegroups.com

Thanks for following!