[Applause]
Hi!
First of all,
I just want to give a big shout-out to the organizers of this conference.
I feel like this has been a fantastic smooth experience from start to finish,
so...
[Applause]
Amazing job.
Hi! I'm Anjana Vakil.
I am an English teacher turned computational linguist
turned software developer
and as I mentioned a little bit earlier today,
about six months ago, I knew nothing about functional programming
and very little about JavaScript.
So, what I want to do today is kind of
take you guys along on some of the things I've learned
about doing functional programming in JavaScript
and I am not an expert in any of this,
so this is going to be me taking you along on my learning journey
and nothing more.
I'm going to try and save a little time for questions at the end,
but we'll see how that turns out.
So, how did I end up standing here
talking to you guys about functional programming in JavaScript?
About six months ago in the fall of 2015,
I went to a programming community in New York City
called The Recurse Center
which quick plug
is probably the best programming community I've ever experienced
and it's a programming retreat
where you can go and learn about
whatever is interesting to you in the world of computer science
and so I got there
and a lot of people were talking about functional programming,
functional programming, Haskell, Clojure, all this cool stuff,
a lot of people were working in JavaScript getting into node
and these were some really interesting topics
and so I started talking to people there
and finding out what is all this stuff.
So, what is functional programming?
Few different ways that question can be answered.
First of all, it's a programming paradigm.
Some other paradigms are like imperative programming
where you say do this and then do that
or object-oriented programming
which maybe a lot of you write object-oriented JavaScript
where you have objects and they have methods on them
and you change them, etc., etc.
Functional programming is also a paradigm
where functions are king
and we'll talk about what that means in a little bit.
It's also a style of coding,
of organizing your code,
writing your code,
style of approaching projects
and really more than that it's kind of a mindset you can get into,
a way of thinking about a problem,
a way of approaching a task
and it's also a really sexy trend
with lots of buzzwords that'll make you super popular
when you're talking with people at the pre-conference party or whatever it is.
No, just kidding.
But it is something that's gotten a lot of attention
and, so yeah, I thought it was important
to find out why everybody was so excited about it.
So, why do functional programming in JavaScript specifically?
Well, I don't know about for all of you,
perhaps more experienced JavaScript developers,
but when I started learning JavaScript
having had some object-oriented programming experience with Java, C-Sharp,
that kind of thing,
I found object-oriented JavaScript super confusing,
prototypal inheritance, how does that work?
How many of you guys, quick show of hands,
have ever run into a bug or a problem or something unexpected with this,
doing something...
Yeah, exactly. Right?
So, I found that really tricky and confusing
and so I thought, all right, I know I want to get more into JavaScript
but let me set aside the object orientation
and try to think about things in a functional way
which is maybe simpler in some ways
and avoid some of these problems
like bugs introduced by binding this to the wrong thing.
So, functional JavaScript to me at least is a bit safer,
a bit less tricky,
a bit easier to debug
but easier to maintain as you're building a project
and we'll take a look at some of the features
that make that easier in a bit.
Also, there is already a huge community of developers
who are doing JavaScript in a functional style,
so there's a lot of libraries out there
to help you write functional JavaScript.
There's a lot of people out there that are experts in this,
for example, there was a talk in the next room over earlier today on Ramda
and there are people here you can talk to
that probably know a lot more about functional JavaScript than I do,
but the point is there's already a community,
so this isn't necessarily something you'd be doing on your own,
grappling you versus JavaScript,
there's other people to support you,
which I found really helpful.
Okay.
So, hopefully by now I've convinced you
that functional programming is at least interesting
and that we could do it in JavaScript to avoid these headaches, etc.
How can we do it?
What does it mean?
This is what I was asking myself.
So, the main thing
and maybe it sounds like a tautology or obvious is that
in functional programming
you want to do everything with functions,
so we want to express everything in our program in terms of functions.
And a function of course is just something
that takes an input and gives an output.
So, we want to be thinking about
kind of the flow of data of inputs and outputs through the program,
instead of thinking about objects and how they interact
and how they manipulate
or thinking about steps in a recipe like in an imperative style.
Here we're really thinking about how we can express everything
in terms of functions,
taking inputs, giving outputs.
So, for example,
this would be a non-functional way for me to get the text
“Hi, I'm Anjana” to appear on the screen.
I could assign a variable, I call it “name”
and have it store the text “Anjana.”
I could have a greeting like “Hi, I'm” or “Hello, I'm”, whatever,
and then I could log that to the console.
This is sort of an imperative style.
First do this, then do that, then do this other thing,
we don't have functions here,
we're not expressing this in terms of how inputs are transformed into outputs.
So, maybe a more functional way of doing the same thing
and this is a really simple example, just for the sake of it,
is to define a function called greet
which takes a parameter name
and returns a string which adds “Hi, I'm”
to the beginning of that name.
So, for example, if I type greet,
the string Anjana,
feeding that as input
then I get the output “Hi, I'm Anjana”,
that's a more functional way expressing this in terms of functions.
Okay. So, another...
maybe the main thing about functional programming
is to avoid side effects
and instead to use pure functions.
So, what does that mean?
A side effect is anything that a function might do
that isn't computing its output from the inputs you've given
and returning that output.
So, for example,
printing something to the console is not returning an output,
it's doing something else,
something that's on the side of the function
or if you have a function that uses some globally defined variable
to compute its output
that doesn't depend only on the input to that function,
so that's not pure.
It's taking something from outside the function
and involving it in some way in what the function does.
So, this is just a really quick explanation of what a pure function
that avoids side-effects would do.
For more information on that
there's excellent Wikipedia articles on these sorts of things,
but basically the idea is that
you want your function to do nothing
except take its input, use that and only that
to compute an output
and then return it.
That's pure.
So, for example, this function here,
we have this globally defined variable name
which gets used in the function
as you can see in the last line there,
it gets used, so there's no input,
we don't have name as an argument to this function,
it's just reading something in from the global state.
That's not pure.
Also, not pure because
the return value of this function here isn't what we care about,
we care about doing something,
changing the world in some way
other than the return value,
in this case, printing to the console.
So, this is a not pure function here.
A pure function might look like this.
Here we have,
the only thing that matters
to the output of this function is its input,
the argument that we pass to it
and the only thing that it does is return its output.
Okay, so I've been talking for a while now about pure functions
that's because this is really like a key thing at least for me,
something I've taken as one of the key parts of functional programming
is thinking about things as purely as possible.
Another key point would be using higher-order functions.
So, this means functions that can take as inputs other functions
or a function that can return a function as its output.
So, basically, we're treating functions kind of as objects themselves.
They can be passed to other functions.
You can have layers of functions within functions within functions, etc.,
and these are what's called higher-order functions,
they come up a lot in functional programming.
This is a bit of a random example,
but let's say we have this function at the top here,
makeAdjectifier
where we give it an adjective
and it returns actually a function.
It doesn't return a string or a number or anything like that,
it returns us a function
which adds that adjective to a string that you give it.
So, for example, I can use the makeAdjectifier function
feed it the input “cool”
and get a function that's called coolifier.
So, now when I pass a string to coolifier,
I get “cool” added to that string.
So, if I pass conference, I get cool conference.
So, the idea here is that we have a higher-order function
which returns a function.
And this kind of wrapping your head around this
at least for me
is one of the key things to being able to write in a functional style
because as we'll see a bit later,
we need these higher-order functions
in order to avoid some of the tricks
that we're used to using from other paradigms.
So, learning the thing to get into that functional mindset
for me really involved wrapping my head around this concept.
Okay.
So, one of these things that we're going to avoid
that we're used to doing is iterating,
using like “for” or “while”, these sort of things.
We're used to going over lists and doing things to all the items in it.
Instead, in a functional style,
we might use higher-order functions like Map or Reduce or Filter
which often take as an input
not only the list that you want to do something to in some way
but also a function that then you're going to apply to it.
In the interest of time I'm not going to go into too much detail
about what Map, Reduce, and Filter do,
but I found and also thanks to my colleague Khalid up there,
a really cool graphic that I think expresses Map and Reduce pretty well,
maybe you guys have seen it before,
the MapReduce Sandwich, everyone!
So, the idea here is that let's say you have a list,
in this case, a bunch of vegetables.
They're whole vegetables.
We got some bread in there too
and we want to transform that data in some way.
So, for example, let's say we want to slice that data
and we have a function ‘slice up’ or ‘cut up’ or ‘chop’
which we can apply to each item in that list.
Now, usually I would do “for vegetable in sandwich ingredients,”
do all of this,
do all this chopping,
but in a functional style we'd use Map,
give it the list of ingredients and give it the function ‘chop’
and I would get out a new list where everything has been chopped.
Then we have a Reduce function
which basically combines all of the items in a list in a certain way,
in this case, layering
to make a delicious sandwich,
and Filter let's say
could be if you hate cucumbers,
you could have a Filter function
which makes sure that
only things that are not cucumbers get through the filter.
So, these are the ways we use these higher-order functions
to get around the type of “for” or “while” iteration
that we're used to doing in functional programming,
instead we're going to feed functions to higher-order functions
like Map, Reduce, and Filter
to get the sandwich that we want.
And again, this is not intended to be a totally clear explanation
of how Map, Reduce, and Filter work,
but there's plenty of information on that online.
The idea is that we want to use these instead of “for.”
So, another thing that we want to do is
we want to avoid mutating data, |avoid mutability.
Mutation in the sense I just mean changing objects in place.
So, when we have something that's immutable,
I'm sure a lot of you guys are familiar with the term,
it's something data that can't be changed in place.
Once we've set it it's there forever.
It's never going to change.
So, let's take a look at an example.
Just because for me
this was another thing that required a little head wrapping.
So, this would be an example of mutation which is non-functional.
We have a rooms variable which stores a list,
so “H1,” “H2,” and “H3,”
because that's what we thought the rooms were,
at least that's what I thought the relevant rooms were,
and then we say no no no actually it's not “H3,” it's “H4”.
So, let's replace the thing at index [2] in rooms with “H4.”
And so, then we have rooms has actually changed,
we went from [“H1,” “H2,” “H3”]
to [“H1,” “H2,” “H4”].
So, that is still stored in the variable rooms
but we've actually changed something in place
and this is something that functional programming avoids
because this can cause a lot of problems
and this is part of the reason why we get into trouble with this
and with these sort of object-oriented approaches,
sometimes you can change things in a way that you didn't intend,
so that what you thought you were dealing with
if I thought that rooms meant [“H1,” “H2,” “H3”]
and I didn't know that somewhere else in my code
I had replaced something in the rooms array
I could run into trouble.
I could end up introducing bugs into my code
and having a really hard time tracking them down
because rooms here is the right thing,
rooms there is the wrong thing,
ah! what happened? Where did this go wrong?
Oh! my God!
You end up crying in front of your computer.
No, just me.
So, a better way to go about things
is to think of all data as immutable, never changing.
For example,
with no mutation we still have our rooms which has the wrong
[“H1,” “H2,” “H3”]
but instead of changing it in place
I'm going to make a new rooms array
using this map function
that we talked about a little bit earlier
where I'm mapping,
I'm feeding a function into this map,
which looks at each room in the list
and if it's “H3”,
oops! I have a missing = sign there,
last-minute slides,
if the room is “H3” it returns “H4” instead of “H3”,
otherwise it returns whatever the room was.
Okay. Understanding this specific example is not crucial
but the point is that once I've assigned this new rooms variable,
new rooms has the correct values I expect “H1,” “H2,” and “H4”.
But rooms is the same as it always was,
it hasn't changed at all.
So, this is thinking about rooms as being immutable,
we're not changing it
and that's something that's really important for functional programming
because as I said,
it helps you avoid a lot of headaches, a lot of bugs.
So, how much time do I have?
Okay. Good.
We have a little time to talk about persistent data structures, yey!
The problem with immutability is that
when you're treating arrays and things like that as immutable,
what you end up doing is making new copies of everything.
So, if I want to change my one room in this list
I have to make a whole new array
and when you're dealing with short little things like this
maybe that's not a big deal,
but as your objects get bigger, more complex,
this can give you efficiency problems
because if you have to copy over everything,
even the things that didn't change,
every time you make one little adjustment
and you want to make a new copy,
a slightly different copy of your array,
it takes you a lot of time,
you have to go through everything in the list to copy it over,
you end up using a lot of space
that maybe once the objects start getting bigger and bigger
becomes a problem.
And so, one thing that's very popular in the functional world
as a way of getting around these efficiency issues
is to use persistent data structures.
This was something introduced sort of theoretically by Phil Bagwell,
he wrote a paper called Ideal Hash Trees.
I can put a link in the slide to that later
and then Rich Hickey who invented the language Clojure
implemented the data structures using Bagwell's ideas
to make Clojure really efficient for these immutable data structures
and for these functional operations.
Okay.
So, the way persistent data structures work if I may,
if you will indulge me,
I'm going to step back to the chalkboard right here.
We're getting retro. Yeah, it's happening.
Okay.
So, if we have like an array where we had H1, H2, H3,
typically what I do in a mutable world is just get rid of this
and replace it with H4,
but as we said we want to avoid that.
So, instead, if I copy it over into a new array,
I copy H1,
I copy H2
and I replace, instead of copying H3 I put in H4.
Great!
But now I have to store two arrays,
taking up a lot of time,
look how long that took me to do all of that.
Terrible. Right?
I know you guys feel as upset about this as I do.
I can see it in your faces.
What if instead we represented this array right here as a tree,
such that each leaf node of the tree
is one of the things that I'm trying to store
or perhaps 2 of the things or 3 or 32 or some number of the things
and if I want to change something,
I don't need to replace the entire array,
I can just make a new node over here, like H4,
and now I can make a new tree
which instead of repeating H1 and H2
I can reuse those same things and just make a new node
which connects them to my new element over here,
so that now I have here a data structure which contains H1, H2 and H4
but I didn't need to make a whole new thing.
I just needed to make my one little part.
I can reuse the old structure of the list.
So, this idea, this sort of topic is called structural sharing
because we can share parts of the old versions with the new versions,
so we have much more efficient operations for adding,
changing things or moving things from vectors, for example, or arrays
and this can also be done for maps, for hash maps that sort of thing
and it basically makes the world of functional programming bust wide open
so that we don't have to go through these long time
and expensive space operations
to update our immutable data all the time.
So, to do this in JavaScript,
there are a couple of libraries that are really popular.
One which I like to use is called Mori
which I'll show you the link for in a little bit
which actually uses ClojureScript
which has these type of data structures natively,
it ports them over to JavaScript,
so you can use them right from JavaScript
and it's great.
It has a lot of also like general functional programming helpers
like Map and Reduce and lots of other things.
There's also another popular library called Immutable.js
which Facebook put out
which is JavaScript through and through.
I haven't worked as much with that
but I know a lot of people like that as well.
And yeah, so these are ways
you can try out using these immutable data structures
if that is something you feel like you can't wait to do now.
I know.
I can just feel the excitement. Yeah, that's great.
Okay. Moving on.
If you're ready to try it out,
like I said, we have Mori and Immutable.js,
links there to those libraries.
There's also a lot of utility libraries
which don't focus so much on this persistent data structure thing,
but instead give you a lot of helper functions like Map, Reduce, etc.
So, Underscore, Lodash, for example.
Today I found out that Ramda is a thing
because there was a talk on it the other day
and there are many more.
And in fact, JavaScript has some built-in functions,
like for example, arrays have a built in Map, Reduce functions.
So, a few slides ago we saw this rooms.map,
that's because the array prototype has these functions Map, Reduce, etc.
So, you can even do some functional programming in pure vanilla JavaScript
without using any of these libraries.
Okay.
So, if you are sitting there thinking,
What? Huh? I didn't really get that something about immutability,
side effects, pure functions. What now, huh?
If you want to learn a bit more about all these buzzwords,
like I said, all these sexy buzzwords
that I've been throwing at you for the last 20 minutes,
I highly recommend a nice gentle introductory article called
“An introduction to functional programming”
by Mary Rose Cook
who is a former facilitator at The Recurse Center
that I keep talking about.
The link is up there,
but basically this is a really nice introduction
that kind of goes into a little bit more depth
in some of the “commandments” of functional programming
that I've mentioned today.
So, if you are a little intrigued
but not quite clear on this stuff that I've been mentioning,
I highly recommend you check it out.
So, I think that's it for my talk.
We have a couple of minutes for questions, I suppose,
eight minutes by my account,
but first of all I just wanted to say thank you guys very much.
I'm Anjana Vakil.
Anjana Vakil on Twitter
and has link there to my GitHub.
So, would love to keep in touch
if anybody else is out there also learning
functional JavaScript as a newbie like myself,
definitely reach out,
we could stick together,
but first of all I want to give a huge thanks
to again the JSUnconf organizers,
especially the diversity sponsors.
I'm here on a diversity ticket myself
and wouldn't have been able to come without that awesome program
and all of you and the sponsors who sponsored those tickets
and also a huge huge thank you to The Recurse Center
and some of the alumni there who have helped me learn all this stuff
including Khalid at the back there
and Sal Becker, another alum,
who explained a lot of this stuff to me
over several long caffeine-fueled conversations at The Recurse Center
and if any of you are interested in spending time
on self-directed educational programming retreat in New York City
definitely check out recurse.com,
it's an amazing community.
Okay, that's it for me. Thanks.
[Applause]
Thank you very much.
Yes, _____
Does anybody have any questions about functional programming?
Don’t know if I'll be able to answer them but I can try.
Yeah.
Actually, always the professors at my faculty
always said that object-oriented programming
is better than functional programming
and I was thinking that is it better
or is it you think that we should use
functional programming only on JavaScript
or also on other programming languages like C _____
So, I think that's a great question
and it kind of gets into a little bit of the,
what I think of as kind of the philosophy of programming paradigms.
So, as I was learning about functional programming
I started even wondering what is a programming paradigm
and why do people fight about them,
why do people say object orientation sucks,
we have to do everything functional
and why do people say no, functional programming sucks,
we need object orientation.
And the conclusion that I came to is that
no one paradigm is better or worse than other paradigms.
They just have different advantages and disadvantages
and they have different situations
in which they're going to be kind of the best tool
for that particular problem.
So, for example, if you just want to really quickly write up a script
that just does something on your computer once really fast,
you're probably just going to do it in an imperative style,
do this, then do that, then do the other thing.
If you don't need to maintain it,
if you just need it to happen right there,
imperative programming is a totally legit paradigm for that.
If you're trying to model real world objects
and how they interact
and how they go around and things you can do,
like if you're trying to model, I don't know,
books in a library
or classes with teachers and students
and how they all interrelate that sort of thing,
maybe thinking about it in an object-oriented way makes most sense
because that's exactly the problem you're trying to solve,
is modeling objects
and that's why that paradigm came about.
But if you're trying to avoid some of those problems
that I was talking about
when you have maybe a situation
that doesn't actually refer to real-world objects,
where you're using objects just because you have to
and that's introducing all kinds of side effects and weird bugs
that are hard to track down,
maybe you want to consider thinking about it
in terms of functions on your data
and things being pipelined through multiple functions
and undergoing various transformations,
not in the sense that the data is being mutated
but in the sense that we're getting new outputs
based on old inputs,
then functional programming is probably the way to go
and it has a lot of advantages such as being nicely,
you can break things down into small functions that only do one thing.
So, if you want to change something
you don't have to change an entire class structure,
you can just change the one little function
that does the thing you want to change.
So, I think it has advantages, it has disadvantages.
I definitely wouldn't say it's better than object orientation in all cases
and I definitely wouldn't say object orientation is better in all cases either,
it really depends on your situation.
Also, very good introduction of programming philosophy.
I used to be a philosophy major, so that might be why.
Any other questions?
You mentioned Map function
and the Map function is not working,
so do you mix it...
Before that, I come from object-oriented programming style
and not so much into functional.
That’s cool too.
The professors really just test our functions
and can avoid the concurrency
that the Map function could possibly introduce.
Non-blocking and concurrency and promises
are all things that I do not feel qualified to talk about right here.
I would love to turn that question over to the audience though.
Anybody want to respond?
_____
Fight fight fight.
Just kidding.
Just kidding, just kidding.
That would be against the code of conduct, you guys.
_____
I would also guess that perhaps it's blocking
but we can discuss this later in a small room or outside.
[Laughter]
Thank you for the conversation starter question though.
Excellent question
and I would love to know the answer.
Look forward to talking you guys more.
I guess...
I guess we are done with the talks, the big talks now.
Thank you.
Thank you. - Again.
[Applause]