DOUGLAS CROCKFORD: So
I'm going to show you some code today. Ordinarily, I don't like talks
with a lot of code in them, because I think they're
tedious and boring. And this talk promises
to be no exception. But code is the story. And so it's not possible
to tell this otherwise. So the topic this morning
is monads. Monads, what are monads? Monads are this strange,
mysterious, weird, but powerful, expressive pattern
that we can use for doing programming. And they come with a curse. The monadic curse is that once
someone learns what monads are and how to use them, they lose
the ability to explain it to other people. There's lots of evidence
of this on the web. Go and search for monads
tutorials, burritos, any of those things, and you're going
to find a lot of really confusing material. So today I'm going to attempt to
break that curse, and show you monads for what
they actually are. So we're going to start with
functional programming. If you can't do functional
programming, then none of the rest of this is going
to make sense. But I'm assuming you're all
professionals, and this should not be difficult material. So there are two senses of the
term functional programming. One of them simply means to
program with functions, so we'll look at that first. Functions enter mainstream
programming with Fortran II. This is a Fortran II function. At that time, lowercase hadn't
been invented yet, so everything was in uppercase. But it looks quite a lot
like a modern function. It starts with the
word function. It has the name of the function,
and parameters wrapped in parentheses,
separated by commas-- really conventional stuff. So it's just a subroutine
that had the ability to return a value. And it returned that value in a
slightly strange way, using assignment statement, which
would assign a value to the name of the function. And then the return
statement would deliver that to the caller. That has been changed since
then, and now everybody has a return statement that takes a
value, and that works better. Or in expression languages, the
last expression evaluated by a function is the implied
return value. But what we called functional
programming only becomes interesting when we
have functions as first class objects. So we can take a function and
pass it as a parameter, or store it in any variable,
or stick it in the field in a record. That's when it becomes
interesting. Then we can have higher order
functions, in which you have functions which operate on other
functions as arguments. And this all became really
good stuff with the invention of Scheme. In Scheme we have what's will
closure, which means that any function has access
to the variables in the outer function. And it turns out that was an
enormous breakthrough. And that is now finding its way
into mainstream languages. Anyone have any idea which was
the first mainstream language to have this feature? It was JavaScript. That's right. JavaScript is leading the way. So the other sense of functional
programming is sometimes called pure functional
programming. And it means functions are
mathematical functions, which is quite different than subroutines that return arguments. Because a subroutine is allowed
to do mutation. And in a purely mathematical
function, that doesn't happen. A function with some input
is always going to have the same output. And the argument in favor of
that style of programming is it makes programs a lot easier
to reason about, because you don't have bugs that will occur
as a result of side effects of something
else happening. If something works, it's
guaranteed to work that way correctly until the
end of time. And that could be hugely
beneficial. But there are problems
that come with that. So you could think of
mathematical functions as being maps. It will simply take some
parameter or parameters, and map them to some value. And that mapping is constant,
and so it always works that way. And so it's easy to predict. So whether functions are
implemented as computation or as association is just an
optimization trick. All functions should
work exactly the same way, either time. So the difference is like the
difference between memoization and caching. Caching is a deal with
the devil, right? We have something, which is
likely to be wrong but is sometimes right, and we don't
know when it transitions from being right and wrong. With memoization, that
never occurs. Once it's memoized it's right
and will always be right. We can take any ordinary
programming language and turn it into a purely functional
programming language by deleting stuff. So we can remove everything from
the language which could have side effects. So we could remove the
assignment statement. We can remove loops, and use
recursion instead if we need repetition. We can freeze all array literals
an object literals so that once minted, they
cannot be modified. In languages like JavaScript,
it means removing Date. Because every time
you call Date, it returns a different value. That's mathematically absurd. Every time you call a function,
it should return the same thing. Same with random. Every time you call random,
you hope to get a different value. But that's that doesn't make
sense mathematically. So we want to remove that. So remove all those things from
our languages, then we'll have purely functional
languages, and we'll also find we're not going to be able to
get anything done anymore. Because most of our programs
are not doing pure computation. They're interacting
with the world. And the world is constantly
changing. And if our programs can't change
with them, then they become brittle and
ineffective. In the real world, everything
changes. And immutability makes it hard
to work in the real world. Now there are pure functional
programming languages like ML, and like Haskell is
a better example. And Haskell is a brilliant
language. And they were doing interesting
computations with it, and then there was the
idea, let's try to do practical stuff in it. And then suddenly it gets
really, really hard. That kind of hard is sometimes
called impossible, because you can't have any side effects. You can't do I/O. How do you
interact with things without being able to do I/O, without
being able to mutate? So they discovered a trick. There was a loophole in
the function contract. And that loophole is that a
function can take a function as a parameter. And once it does that, every
time a function is called with a function, every function is
going to be different, because every function is a unique
thing, which is closed over the thing that created it. And so it sort of gives us
a way to escape from the side-effect-free thing. You just need to start thinking
about how you compose functions in such a way that
you have the illusion of having mutability without
actually mutating anything. So the Haskell community had
reason to adopt something called the I/O monad, because
it gave them the ability to act as though the language had
I/O, even though it didn't. And so as they're calling
things, they can be assembling state, and that state kind
of follows forward in the computation. And it kind of works. It's like, hurray. It could be used for practical
programming, except it's kind of hard. And it turns out that you want
mutation, because that is how the world works. And so the I/O monad is a
solution to a problem you should never have. But it turns out there are lots
of other monads, and so they're still worth
taking a look at. There's some who will say, in
order to understand monads, you first have to learn Haskell,
and you have to learn Category Theory. If you don't know these things,
there's just the no way to start. You can't learn monads. I think that is true in exactly
the same way that in order to understand burritos,
you must first learn Spanish. And they're true in the same way
in that neither is true. It turns out you can do a lot of
stuff with burritos without knowing any Spanish. You can order them. You can eat them,
and enjoy them. You can even learn
to make them. You can even learn to invent new
kinds of burritos, which you and your friends
can enjoy. And you can do that without
learning any Spanish. I'm not saying you shouldn't
learn Spanish. There are lots of good reasons
to learn Spanish. You can learn a lot more about
Mexican cuisine, for example. And that will allow you to
make burritos and other things, which are more
authentic, and perhaps even better. It'll allow you to have
interactions with some wonderful people you would never
interact with otherwise. And if you're one of the job
creators, it gives you an opportunity to talk directly to
the people who are actually doing your work for you. That's a good thing, right? So in the same way, it's
good to learn Haskell. Haskell has a lot of
good stuff in it. It can teach you a lot. It's a good language to learn. It's just not necessary to
learn Haskell in order to understand monads. Some people will disagree with
me, and say no, you have to start with Haskell. And I say no. If you have the chicharrones,
you can learn monads without Haskell. Some people will say, well you
at least have to start with the types, that you need
a really strongly typed language, or a super strongly
typed language in order to manage monads. You have to understand
this before we begin. And I'm going to tell
you, no, that's actually not true, either. Haskell has a wonderful
type system. And it does a lot of type
inference, so that you can under-specify what the program
does, and it will try to figure out all the types. But it doesn't always
go right. And so if it is trying to solve
your program, and it finds an inconsistency,
it stops. And you get this completely
opaque message, which is indicating that it found an
inconsistency in a place which is probably miles away from
where the error actually is. And so getting that stuff
to work and compile can be really hard. And once it's done, there's
folklore which says, having gone through that ringer, you're
guaranteed your program is going to be error free. And it turns out it's not, that
there are subtle errors that happen in Haskell, as
happen in all other languages. And the type system actually
gives you no leverage in dealing with that stuff. Stuff gets complicated, and
when there's complexity, things go wrong. And that happens in
all languages. It turns out that it's easier to
reason about monads if you don't have to deal with
the type stuff. You don't actually need to
understand what that is in order to build a monad. Now there's some who will say,
no, that's not true. You don't dare go that
way otherwise. But I say, my friends, if you
have the huevos, you can. So what do you say we sock up
and look at some monads? It turns out, the language you
need to learn first is JavaScript. Because it has the higher
order function stuff that we need. And it doesn't have any the type
stuff to get in your way. So you can just think about
what's going on. So what we have here is a story
of three functions. We have a function called
unit that takes a value and returns a monad. We have a function called bind,
which takes a monad and a function that takes a value
that returns a monad. That's it. So all three of these
functions return monads, and that's it. That's monads. Thank you very much. So you're probably wondering,
still, what is a monad. A monad is an object
in this case. It could be something else. But generally it's an object. So if you know anything about
JavaScript, you're looking at the unit function, you're
going, wait, unit is a function that takes a value and
returns an object, so it must be a constructor. And yeah, right., that's
exactly right. So unit is constructor. So nothing magical there. So all the magic must be
in the bind function. So that's it. And there's not a
lot of magic. So there are three axioms that
you have to hold in order to be a monad. The first to describe the
relation between bind and unit, which is basically that
unit creates a monad that represents some value, and the
bind function allows another function to have access
to that value. The interesting axiom is the
third one, which tells us how we can do composition
on the bind method-- that we can have nested bind
methods, and that does the same thing as calling
bind with a function that calls bind. That's it. That is monads. Now we can make it easier to
deal with these monads by converting it from functional
notation into methodical notation. That's a really easy thing
to do in JavaScript. Everybody does that
all the time. You need to understand the
mapping between functions and methods, and once you can do
that, then we can very easily transform the way we invoke
the blind method. Instead of saying bind passing
a monad, we'll call the monad's bind method. It's just an easier
way to do that. Some languages, say Common Lisp,
you would recognize that there are lots of different
possible varieties of monads that you might want to
implement, but they all have the same basic pattern. So you'd want to implement some
kind of macro to make it easier for defining all those
different kinds of monads. JavaScript unfortunately
does not have macros. But it does have functions, and
so we can create a special kind of function called a
macroid, which acts like a macro, which helps us
to do that kind of thing that macros do. So this is one of
those macroids. I want to say something
about the coloring. You've all seen syntax
coloring, right? That's something we put in our
text editors to make it easier for kindergartners to
do programming. Because each of the elements of
the language is a different happy bright color, and so it's
easy to recognize, oh that's a variable, and that's
a string, and so on. I don't get a lot of value out
of that because I am more of a grown up, and I'm a professional
programmer. And I really don't need the
colors to figure out what's a variable and what's a comment. But when I'm doing functional
programming, I would like to have color help me deal with the
nesting of functions, and deal with the closure. So I wish someone would
make a text editor for me that does this. So I want all my global-level
stuff to be white. All the top-level functions,
I want them to be green. The functions defined inside
of those would be yellow. The ones inside of those would
be blue, and so on. But the color of a variable is
the color in which it was defined, and that allows me
to see how things close. It gives me a view of the
visibility of the variables and their life expectancy,
and so on. And that turns out to be
really useful stuff. So I'd really like to have this
kind of colorization. And I'm going to be using this
sort of colorization through the rest of this talk. So we've got our macroid. And we're going to use
it to define a monad. And we're going to start with
the identity monad. So the identity monad will
build the identity constructor. And we'll call the identity
constructor, passing it the "Hello world" string. And then when we call
monad.bind, passing alert, the alert function as its method,
we'll get the "Hello world" thing. So this is the simplest slightly
useful monad, the identity monad. Let's look at the axioms again,
using the methodical notation that we just
came up with. We previously looked
at it functionally. Now we look at it
methodically. And I think it actually makes
more sense in this notation. I think it's easier to see what
the relationship between unit and bind is. But even better is the thing
that happens in composition. We now have this thing where
we've got a monad. And we call bind. And it returns another monad. And we can call bind again. This is a much easier
composition pattern than the other one, in which we had bind
nested inside of bind, because with the nesting, you
have to read the expressions from the inside out. And that's a hard thing
for us to do. But in the methodical
form, we can read it from left to right. And so composition
is a lot easier. I can just keep tacking things
on, and the thing keeps getting longer, and more
interesting, more complex. Any of you who have ever done
any Ajax programming might notice there's something about
this pattern that's familiar. I've got an object. I call a method on it. Then I call another method
on the result. Where have I seen that before? It's the Ajax monad. All of the Ajax libraries
do this-- JQuery, YUI, everybody. We've been doing
this for years. It turns out we've been doing
monads all along. This is an example of something
I did in 2001. The Interstate library was my
third JavaScript library. The first one was just something
to help me manage the differences between Netscape
4 and IE 4, which were horrendous. And after I wrote that, I
looked at what sort of patterns we were using in using
it, and then trying to figure out a way to incorporate
more of that into the library to make
it easier to use. And this is my third
iteration. And in this one I realized that
if I have an object which wraps a DOM node, in this case,
a text form node, and if that object, that monad keeps
returning itself, then I can cascade all of these
other things on it. And it becomes really
expressive. And lots of other people
figured this trick out as well. And so this is now standard
equipment in Ajax libraries. In 2007, I developed a system
called ADsafe which was intended to make the web safe
for doing online advertising. And it took the same idea of
taking a node and wrapping it in a monadic object, but
also added a security dimension to it. So it would guarantee that there
was no way that the node could be extracted
from the object. So that meant we could give one
of these ADsafe nodes to a piece of untrusted code, for
example, an advertisement, and be confident that it could not
break the containment, that it was only able to do with that
node what we intended it to be able to do with that node,
and nothing else. It couldn't use it to traverse
the rest of the document. It couldn't use it to
get to the network. It couldn't use it to
steal our cookies. It couldn't do any
of those things. All it could do was display
an ad in that window. And ADsafe worked. And it used the same
monadic pattern. So let's improve our macroid to
allow us to do Ajax stuff. So we've already seen we
can take an object and call a bind on it. But what we really want
to be able to do is call a method on it. Also, we want to be able to
have methods pass some variable number of parameters,
as well. So we'll expand our bind method
to now take an optional second parameter, which is an
array of the arguments that we want to get to the method. And we'll extend our macroid by
first creating a prototype object, which will be an object
which inherits nothing. This is where we're going to
keep the methods of the monad. We can use object.create of
null to make that for us. It makes an object that
inherits nothing. This is a great new feature
that came in the ES5. And then when we create our
monad, we will have it inherit from that prototype object. So anything that goes into the
prototype object will be inherited by the monads
that we make. Then we'll modify the blind
method to take the second argument, which is the set of
arguments that we want to pass into the method. And unfortunately, because of
a profound stupidity in the way JavaScript was designed,
we have to manipulate the arguments object. And that's really
hard, because it is not a real object. And so the things you have
to do to it are horrible. Fortunately, ES6, the next
edition of the language, will probably have this dot dot dot
operator, which happens to do exactly the right thing. This is going to be my second
favorite feature in ES6 if it ever comes out. So I'm looking forward
to that. Because it took those three
extremely ugly lines, and turned it into one very neat
line, which obviously does what it does. We're then going to create
a unit method on the constructor, which will allow
us to add additional methods to the prototype. It simply takes its arguments,
and assigns them to the prototype, so that's
pretty easy. And it also returns unit, so
that we can then call dot method dot method dot method
on the constructor. So it's monadic in that
dimension, as well. But we can do even
better than that. It assumed that the functions
that get called to method understand about monads. But in some cases we want to be
able to wrap functions that know nothing about monads,
but have them work in the monadic context. So we're going to add another
method to the constructor, called lift. And lift will take an ordinary
function and add it to the prototype. But it will wrap that function
in another function, which will call unit and bind,
as suggested in the first two axioms. So that it allows that function
to act as though it knew about monads, even
though it didn't. So it'll call bind for us, and
it will then wrap it's result in a monad if it needs to. So this makes things
a lot easier. So let's use this one. We're going to call our
macroid again to make our Ajax monad. And we're going to use
lift to turn alert into a method on it. So we could change
the name here. But we're going to keep
the name the same. We're going to take the alert
function, and use it as the alert method. So now I can call the Ajax
constructor to make my monad. And the monad now has
an alert method. And if I call it, it'll say,
"Hello world." Hooray. It turns out we've been
doing this for years. We just didn't know it. Ajax has always been monadic. One of the difficulties we have
in some of our modern languages is the problem
with null. Null as the thing that
represents a value that is not there. And if you try to do something
to null, generally something bad will happen. Sometimes it seems that Java
was optimized for the generation of null pointer
exceptions. So you end up having-- the null pointer exception
doesn't actually ever tell you anything, except that there
was a null that you didn't check there to avoid. And so your code tends to get
filled with lots of, if null, don't do that, if null,
don't do that. Which is just a waste of time. It's completely unproductive. We knew we didn't
want to do that. We shouldn't have to say so
every time we touch a variable that might want to null. So there's a thing called
the maybe monad. The maybe monad takes null
pointer exceptions and simply removes them from your model,
so you never have to worry about them anymore. It's similar to the weight
that NaN works. A long time ago, in Fortran and
another languages, if you ever accidentally divided
something by zero, your program would stop. Exception, thing crashes,
cores, done, stops. So as a result, you had to
write in front of every division, but if we're
dividing by zero, then don't do it. You never intended to have it
happen, but you had to guard against it all the time. So we now have NaN. And NaN represents
Not a Number. It's sometimes the result
of dividing by zero. And so if we divide by zero,
we get NaN instead. And the program keeps going. At the end you can ask, by the
way, is the answer NaN. No, OK, something happened. We can ignore the result. So that's much nicer than having
to put guards around every operator to
make sure that nothing's going to go wrong. The maybe monad allows us to
do a similar thing with pointers or references,
so we don't have to worry about that anymore. Those errors don't happen. So we're going to modify our
macroid in order to be able to deal with maybe monads. So we're going to add a
parameter to the macro, which takes a modifier function. And that modifier function will
allow us to intercept things that we're
constructing. So the unit method, as part of
its doing work, will look to see if the modifier function
is present. And if so, it will call
it, passing the monad and the value. And that will allow that
function that we pass in to do something with the thing
that we're making. One way we can do that is we can
use the macroid to make a maybe monad by passing in this
function, which will look at the value, and see if the value
is null or undefined. And if it, then we go, this is
going to be a null monad. And it's going to have this
amazing property, in that we're going to change its bind
method to do nothing. It will simply return
the monad. So it turns it into an identity
function, and crashes don't occur. So now we can make
our maybe monad-- this case, we'll make
a null one-- and if I call bind on alert,
nothing happens. It's great. So if you incorporate this
kind of stuff into your system, you never again
have to worry about null pointer errors. It's just amazing. They just go away. Bind will prevent it eve from
getting called, and everything works right, which is nice. It's a liberating thing. So that's our friend the monad. That's it. And we looked at three specific
monads-- the identity monad, the Ajax monad,
the maybe monad. There are lots more,
but they're all variations on this pattern. And now that you've been through
this talk, you might want to look at the other
monad tutorials. Go to Bing and Google for
monad burrito, and see what you find. It's going to be
baffling stuff. But it'll work. So I have some time left. So I want to talk about
concurrency. Concurrency is when you try to
make lots of things happen at the same time. And there are a number of models
for how you do that. The most popular is
to use threads. And the problem with threads
is that they are evil with respect to mutation. If you have a process that's
trying to do read, modify, write, and another process
that's trying to do read, modify, write, and they're doing
it on the same memory, there's a strong likelihood that
they're going to clobber each other. That's called races. And races are horrendously
bad for reliability. The way we mitigate that is
with mutual exclusion. Mutual exclusion has its
own set of problems. It can cause bad performance
problems, or more likely it's going to cause deadlocks
and starvation. And that's a bad thing too. There are a couple of
other alternatives. One of them is to go with purely
functional programming. Because when we're purely
functional, we never mutate. And so that's not a problem. But not mutating is
its own problem. Another alternative is turn
based processing. This, I think, is the
right way forward. So in a turn based system,
everything is single-threaded. An as a result we are race
free and deadlock free. That turns out to be great. But it requires that we respect
the law of turns. The law of turns says, your
code must never wait. It must never block. And it must finish fast. A turn cannot sit there
and loop, waiting for something to happen. It has to get out as
quick as it can. So not all programs can be
easily adapted to that. But it turns out quite
a lot of them can. So event driven systems
tend to be turn based. Message passing systems
tend to be turn based. You don't need threads. You don't need mutual
exclusion. It's a much simpler programming
model, and it's really effective. It turns out all web browsers
use this model. Most UI frameworks
use this model. So it's something we've been
doing a long time, anyway. We're now seeing this model
getting more popularity on the server side. So there's Elko for Java. There's Twisted for Python. No JS for JavaScript. Take the same turn based model,
and make it available on the server. Now some people complain
that asynchronicity can be hard to manage. And there are some things
you need to do in order to adapt to it. One of the problems is that if
you have multiple things that each serially depend on each
other, the naive way to write that is with nested
event handlers. And that turns out to be
extremely brittle patterns. So you don't want to do that. A much better alternative
is to use promises. Promises are objects which will
represent a future value, and a way of interacting
with that future value. So promises are an excellent
mechanism for dealing with asynchronicity. Every promise has a
corresponding resolver, which is used ultimately to assign
a value to that promise. And once the value is assigned,
then interesting things can happen. So a promise, when it's created,
will have one of three states. First state will be pending. And depending on what happens
to it in the future, it can change to either
kept or broken. Or it may always be pending. So a promise is an
event generator. Once the promise is resolved,
then it can fire events on consumers who are interested in
the result of the promise. So at any time after making a
promise, an event handling function can be registered
with the promise. And those will then be called
in the order in which they were registered when the
value was known. And a promise can accept
functions that will be called with a value, once the promise
has been kept or broken. And we can do this with
the when method. The when is sort of like on. It allows us to register event
handlers, but it will register two of them-- one to be called
if the promise is kept, and the other to be called it
the promise is broken. So here's a function for
making up a promise. I'm calling it vow. So a vow will produce
an object. And that object will have
three methods-- keep, break, or promise. Promise is not actually
method. It's an object, which represents
the promise itself. So I can take the promise
and hand it to you. And in the future, when I know
what the result of that promise is, I can call either
keep or break, and then your promise will change its state,
and good things happen. So here's an example. One of the problems with
filesystem APIs, going all the way back to Fortran,
is that they block. If I want to read something from
the card reader, or from the terminal, or if I want to
send something to the printer, or to the disk drive, my program
stops until that operation has completed. In some cases, my program can
stop for a long time. I don't want to stop, because
that breaks the law turns. The law of turns says
I never stop. I never break. I have to finish. A way to do that would be to
have the file system, instead of blocking, it immediately
returns a promise. So my program can then
continue going. I'm not blocked on it. So here I've got a read
file instruction. Name is probably the
name of the file. And it's going to return
a promise. And I can tell that promise,
when you are resolved, call my success function. And it will receive the result
of the file operation, and things are good. And if the file operation failed
for some reason, like file not found, or whatever,
then call my failure function instead. You might be wondering why do
you call my failure function? Why don't you just throw
an exception? You have to think about this
stuff as time travel. So what an exception does is it
unwinds the stack to some earlier point in time. And we can then recover
from that point. But in a turn based system, the
stack gets reset all the way down to zero at the
end of every turn. So there's no way I can unwind
into a previous turn, because the stack is gone. There's no way to
go back in time. You can only go forward
in time. So we need eight time travel
mechanism which goes forward. It turns out promises do that. That's the whole point. So promises can have a positive
consequence or a negative consequence. That negative consequence
is like an exception. So the way we deal with
exceptions is by having failure functions instead, which
will be called in the future, once we know that the
thing actually failed. I think I said all of that. Exceptions modify the
flow of control buy unwinding the state. Turn based system, the stack
is emptied every turn. One of the nice things about the
way failure functions work is that we can nest promises. So each when actually returns
another promise, based on the resolution of that
particular when. And we can cascade
those, as well. So we can say, when we know the
result of that, do this. When we know the result
of that, do that. And so on. And if any of those fail, and
if they don't specify their own failure, then the
failure propagates. It's contagious. It goes forward. And so the last one, the last
failure specified, will catch all of the previous things. So it acts like a try, except
this is something that's happening over many,
many turns. So it gives us a way to
manage asynchronicity. So one of the nice things about
promises and the when method is how they compose. So when I say .when.when, that's
doing the same thing as when passing in a function
which calls when on another promise. And some of you might be
thinking, wait a minute, this looks eerily familiar. Where have I seen this before? You might be thinking, this
looks like the third axiom. I would say, you are right. This is the third axiom. It turns out promises
are monads. Now they're a different kind
of monad, because all the other ones we've looked at,
the value of the monad is known at the time that
it's created. And because it's purely
functional, that value cannot be modified. This is a little different,
because we don't know the value at the time that
the thing's created. That's going to be resolved
in the future. So it gets filled in later. Also because monads don't have
the problem where they might fail to ever get that value,
we only need to provide one function to bind. But when needs the ability to
have two functions, because it has to deal with
a failure case. But otherwise, it works exactly
like the monads. Let's look at how we could
build the vow function in order to do this. Now this is about a page
worth of code. And I'll show you the page at
the end, but you're not going to be able to read it. So I'm going to be zooming
in on pieces of it. So we've got a function that is
going to return an object. And that function is going to
have a couple of functions in it that the yellow function
will close over. That's one of the nice
construction patterns that we have. And the thing that we're
assigned to vow is not the green function, it's the result
of the green function. Because we're invoking it
here, at the bottom. So that little pair of parens
is really easy to overlook. But it turns out it's
really critical to understanding this. So just leaving it hanging out
there like a pair of dog balls, I don't think is
useful to the reader. I want the reader to
have a bigger clue that this is important. So I recommend wrapping
the entire implication expression in parens. So it makes a lot easier for the
reader to see this is all part of the same thing. This is important. If I see a function in parens,
that probably means something. And I need to look for that. OK, so let's zoom in on
the make function. It's going to have a couple of
arrays where it's going to keep the success functions and
failure functions that get registered with it. It's going to have a variable
for the ultimate fate of this promise, once it's known. Its status starts
off as pending. JavaScript doesn't
have symbols. It doesn't really need them,
because strings were implemented correctly. Two strings containing the same letters are equal, which-- it would be stupid for them not
to be equal, wouldn't it? And then it returns of an object
containing the break method, the keep method,
and the promise itself, which is an object. We'll look at its construction
in a moment. And break and keep both call
a herald function, which is going to announce
to the world the resolution of this promise. So we'll look at herald. Herald can only be
called once. So if the current state is not
pending, then we can throw. In this case, throwing is OK,
because it's a local thing. It's not something that
we need to throw into a different turn. We'll set the fate, and we will
enlighten the queue of waiters, and let them know
that the fate is known. And we'll then zero out the two
queues to make sure that none of those functions
ever get called again. So let's zoom in on something
else now. We're going to zoom
in on the promise. The promise will have a property
that just identifies itself as a promise, to make
it a little easier to recognize it. And it contains the
when method. The when method is going to
register the two event handlers that depend on the
result of the promise. And how it will do that will
depend on the current state of the promise. If they're pending, then they
simply get added to the queue. If the promise has already been
resolved, then it will, depending on whether we're
relying on the failure case or the other case, will queue
it and then enlighten immediately. So it doesn't matter when the
promise is resolved versus when we register with
the when method. So there's no race there. You can register after the
promise is resolved, and it works exactly the same way. You don't need to care about
how that race may occur. And then at the end, we
return the promise. This is the business that
happens when cue the thing. I'm getting bored now, so I'm
just going to skip through this stuff. And there's that. So the code is available
on GitHub, if you want to play with it. It's all written
in JavaScript. This is it. There's just one page. You might want to
write that down. So our friend, the monad. So we saw the identity monad,
the Ajax monad, the maybe monad, and the promise monad. I contend that promises
are monads, which-- this is my contribution
to this, I guess. I don't think this result
had been known before. Don't forget your semicolons,
people. It's really important. I've got some further
viewing for you. Carl Hewitt was at MIT. I think he's at Stanford now. He came up with the actor model,
which inspired the development of the scheme
language, and a lot of other stuff. I think the actor model contains
the solution to most of our problems. But Carl has not written any
accessible material about it. It's all kind of-- you're read it, obviously. It's scary stuff. But he did do an interview with Channel Nine at Microsoft. It's actually a very nice
introduction to the stuff. So I recommend you take
a look at that. Channel Nine apparently likes
the really long URLs. I doubt that there's anybody
in this room who could actually type that in. I'm sure if you go search
for it, you should be able to find it. Then Mark Miller is one of the
first people to come up with promises, which is based on an
idea called futures, which also came out of Carl's
actor model. He's implemented it in a
number of languages. And you just saw an
implementation in JavaScript. He has a really interesting
couple of talks that are available on YouTube, which talk
about this, and some of its implications for doing
automated contracting, and financial instruments, and
lots of other really interesting stuff. So I recommend you take a
look at that as well. It's certainly worth
your time. And Miller works here,
by the way. He is a Googler, good guy. And that's it. That's all I've got
for you this hour. Think you and good night. MALE SPEAKER: I'm guessing you
have a few minutes, maybe to answer a couple of questions? In an effort to keep the video
in sync with questions, I've got a lav here. So I walk around to anybody who
wants to ask a question, just so we can capture it. And while we're talking
about that, nothing confidential, please. This will be going public
afterwards. Do you want to start? AUDIENCE: Thanks for the talk. I was wondering, what's
your take on the cancellation of promises? Because that's one of the
questions that hasn't been really resolved. Cancellation of promises, when
I register my listener to a promise, and I'm not interested in the result anymore. DOUGLAS CROCKFORD: So that's a
really easy thing to resolve on your side. You can have a Boolean at the
top of your responder, which says, am I interested
anymore or not. So you can do it that way. But promises also compose
really nicely. You can cascade them
together and stuff. So you can have a canceller
in that string. You can compose cancellation. There are lots of higher level
patterns that you can build out of the simple promises. AUDIENCE: Is there a way to
communicate to the resolver that you are not interested
anymore, therefore it doesn't need to do the work
to generate-- DOUGLAS CROCKFORD:
Is there a way to communicate to the resolver? Not in the promise
system itself. But you can always
send it message. And it's similar to a problem
you might have in, say timers. You can have a queue
of timers. You might want to say, I'm not
interested in this timer anymore, and so you
want to cancel it. But it might be that by the time
you get the cancellation to it, it's already fired. So it's likely you're going
to experience races. So that's probably not a pattern
you want to pursue. But it is available to you. AUDIENCE: It seems that
debugging is a real challenge for turn based programming. If you set a break point in a
conventional program, you can see the call chain that
gave you the context for why you're there. You could step over
subfunctions, and skip whole sub trees of the evaluation
tree. And that seems to be a lot more
complicated in debugging. Is there practical tools for
debugging turn based programs? DOUGLAS CROCKFORD: I think it's
a lot easier than trying to debug threads. The hardest thing I've ever done
in my career is try to debug a real time problem where
two threads were chasing each other. I think turns are a lot easier
to manage than that. Debugging is always
going to be hard. And as we get more temporal
complexity, it gets harder. But I think turns manage that
complexity much better than threads do. MALE SPEAKER: As soon as I have
the floating mic, I'm going to make my way to
the front in a second. We've got one more here. AUDIENCE: Do you have any
thoughts on emulating do-notation in JavaScript? Have there been any
attempts at that? DOUGLAS CROCKFORD:
Thoughts on what? AUDIENCE: Emulating
do-notation? The monadic do syntax. DOUGLAS CROCKFORD: No. One thing we're seeing in
JavaScript now is a lot of experimentation with
new syntax. Coffee scripts launched that-- there were other examples
before that. But there are lots of people who
were trying to experiment with changing language, or
making it more expressive. I expect we'll see that
research continue. We don't see promises
as a feature in the ES6, possibly ES7. But I'm not confident as to
what's going to make in the ES6 right now. So it's dangerous to predict
what's going to be in seven. And whether it will bring new
syntax with it as well, I don't know. AUDIENCE: Is the cost of making
closures in JavaScript make these monadic approaches
infeasible right now? DOUGLAS CROCKFORD: No, closures aren't that expensive. They're just function objects. And they're great. A lot of stuff gets
enabled by this. You could take a simpler
approach to some of these things. There is a cost. But very few of our JavaScript
programs are compute bound. We're mostly bound by
everything else. So I don't think
it's a concern. I think this is easily
affordable. AUDIENCE: Is this
a public video? MALE SPEAKER: Yes. Any non-competition questions? You guys are quite a bunch. All right, I think you stunned
into silence, Douglas. DOUGLAS CROCKFORD: All right. Thank you.