We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

JavaScript Combinators, the “Six” Edition

00:00

Formal Metadata

Title
JavaScript Combinators, the “Six” Edition
Title of Series
Number of Parts
133
Author
License
CC Attribution - NonCommercial - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
JavaScript's first-class functions are the basis for nearly everything in the language, including methods and constructors. In this talk, we'll explore functions that consume and return functions, and see how they can be used to build expressive programs that hew closely to JavaScript's natural style, while taking advantage of ES6/ECMAScript 2015’s new features.
Software developerJava appletScripting languageCombinatory logicCombinational logicRegulärer Ausdruck <Textverarbeitung>Process (computing)Descriptive statisticsScripting languageJava appletWeightFunctional programmingArithmetic meanWordMultiplication signComputer programmingConstructor (object-oriented programming)Computer animation
Software developerFunctional programmingPoint (geometry)Dependent and independent variables
Software developerParsingQuery languageLoginElectric currentHelmholtz decompositionFunction (mathematics)CodeMereologyObject (grammar)Query languageElectronic mailing listLevel (video gaming)MultiplicationSystem callFormal languageQuicksortInheritance (object-oriented programming)Programming paradigmFunctional (mathematics)Multiplication signTorusCartesian coordinate systemComputer programmingDependent and independent variablesWeb 2.0Execution unitContext awarenessSingle-precision floating-point formatComputer animation
Software developerCAN busParsingFunction (mathematics)Electric currentQuery languageDifferent (Kate Ryan album)Moment (mathematics)Data structureFunction (mathematics)Functional (mathematics)Video game1 (number)
Software developerHelmholtz decompositionProgramming paradigmPower (physics)BitForm (programming)Ideal (ethics)Moment (mathematics)SoftwareAssembly languageControl flowHelmholtz decomposition1 (number)Computer animation
Software developerFunction (mathematics)Function (mathematics)Functional programmingObject-oriented programmingProgramming paradigmFormal languageFunctional (mathematics)ImplementationCASE <Informatik>BitPlotterNumberLibrary (computing)Process (computing)Descriptive statisticsObject (grammar)
Software developerRevision controlCategory of beingGamma functionMereologyInterface (computing)Function (mathematics)NumberBitGroup actionTask (computing)CASE <Informatik>ImplementationElectronic signaturePlotterElectronic mailing listParameter (computer programming)Cartesian coordinate systemDependent and independent variablesDot productFunctional (mathematics)Functional programmingCategory of beingComputer clusterFunction (mathematics)Interface (computing)SoftwareBlogType theoryLibrary (computing)Euler anglesQuicksortProcess (computing)NP-hardMereologyFormal languageScripting languageReal numberSlide ruleDifferent (Kate Ryan album)Self-organizationPartial derivativeMappingForm (programming)WordReading (process)Computer programmingConnected spacePoint (geometry)Goodness of fitData storage deviceOrientation (vector space)Computer animation
Software developerInterface (computing)Helmholtz decompositionInterface (computing)Code refactoringCodeLibrary (computing)Helmholtz decompositionFunction (mathematics)Partial derivativeDifferent (Kate Ryan album)Cartesian coordinate systemForm (programming)Term (mathematics)Functional (mathematics)BitImplementationIdentity managementFlow separationComputer animation
Software developerFunction (mathematics)Category of beingPartial derivativeFunction (mathematics)Functional (mathematics)Term (mathematics)MereologyDot productKeyboard shortcutCartesian coordinate systemMathematicsAbsolute valueParameter (computer programming)Product (business)System callPartial derivativeInterface (computing)Moment (mathematics)Helmholtz decompositionExpressionFunctional programmingSpacetimeScripting languageForm (programming)Computer clusterJava appletPlotterComputer animation
Software developerMereologyFunctional programmingComputer scienceFunction (mathematics)Scripting language
Category of beingPartial derivativeSoftware developerFunction (mathematics)Combinatory logicHelmholtz decompositionObject (grammar)Function (mathematics)CodeCombinational logicCategory of beingObject (grammar)MathematicsSystem callParameter (computer programming)LogicFunctional (mathematics)Multiplication sign2 (number)Military baseBlogString (computer science)Dynamical systemBuildingScripting languageOrder (biology)Formal languageOperator (mathematics)ExpressionGreatest elementRight angleQuicksortIdentity managementArithmetic meanMessage passingComputer animation
Helmholtz decompositionSoftware developerFunction (mathematics)Functional (mathematics)Object (grammar)MathematicsQuicksortPhysical systemSoftwareMultiplication signControl flowComputer animation
Level (video gaming)Software developerCombinational logicLevel (video gaming)Function (mathematics)MappingSlide ruleControl flowHelmholtz decompositionQuicksortContinuous functionComputer animation
Software developerGroup actionFunction (mathematics)Functional (mathematics)MereologyGoodness of fitCombinational logicPartial derivativeSlide ruleCASE <Informatik>Computer fileCartesian coordinate systemSoftware testingPoint (geometry)Sampling (statistics)MathematicsLine (geometry)Software bugSystem callLevel (video gaming)Computer animation
Software developerMessage passingCodeDatabaseTable (information)SoftwareDiagramComputer clusterBitCovering spaceTheory of everythingReal numberProduct (business)Multiplication signComputer animation
Software developerFunction (mathematics)Combinatory logicQuicksortWordPhysical systemSoftwareMereologyFunction (mathematics)Combinational logicMixed realityData structureMultiplication signDesign by contractFamilySystem callPresentation of a groupReal numberForm (programming)Similarity (geometry)WritingFunctional (mathematics)AbstractionBitOnline helpAuthenticationLevel (video gaming)Principal idealException handlingView (database)Slide ruleComputer animation
Software developerJava appletScripting languageQuicksortCodeSet (mathematics)Formal languageFunctional (mathematics)Graph coloringLatent heatMultiplicationScripting languageGreen's functionBit rateInterface (computing)Wave packetFunction (mathematics)Whiteboard
Software developerConstructor (object-oriented programming)Social classPrototypeInheritance (object-oriented programming)Functional (mathematics)Function (mathematics)WritingProduct (business)Revision controlLibrary (computing)QuicksortDependent and independent variablesMultiplicationBitObject (grammar)TowerExpressionSlide rulePattern languageSocial classOrder (biology)AuthenticationElectronic mailing listFormal languageCodeSystem callMixed realityGame controllerPresentation of a groupWordProbability density functionScripting languageRoyal NavyComputer clusterComplex (psychology)PrototypeControl flowDeclarative programmingNumeral (linguistics)Film editingTask (computing)Fitness functionCASE <Informatik>Java appletComputer animation
Software developerSocial classFunction (mathematics)Functional (mathematics)Level (video gaming)ExpressionBitCompact spacePositional notationComputer clusterDemosceneWordGraph coloringResultantPRINCE2
Software developerFunction (mathematics)Interface (computing)Social classFunction (mathematics)40 (number)Interface (computing)Goodness of fitSocial classCartesian coordinate systemMereologyKeyboard shortcutDependent and independent variablesLine (geometry)CodeRevision controlComputer animation
Software developerHelmholtz decompositionSocial classComputer programmingDependent and independent variablesPresentation of a groupFunction (mathematics)Functional (mathematics)Order (biology)Computer animation
Software developerCache (computing)ComputerMereologyRight angleFunctional (mathematics)Bit rateOrder (biology)SoftwareComputer programmingFundamental theorem of algebraFunction (mathematics)Validity (statistics)Software developerComputer animationMeeting/Interview
Software developerService (economics)CodeMUDMereologySoftwareComputer animation
Software developerCombinatory logicFormal languageCodeConstraint (mathematics)Combinational logicComputer programmingMereologyMultiplication signSoftwareFunction (mathematics)Functional (mathematics)Cartesian coordinate systemPartial derivativePresentation of a groupType theoryHypothesisFormal languageComputer animationPanel painting
Software developerFunctional (mathematics)Numbering schemeMereologySpacetime19 (number)Electronic mailing listWordSoftwareHydraulic jumpObject (grammar)PlastikkarteQuicksortFunction (mathematics)
Software developerGraph coloringPlastikkarteSubject indexingQuicksortPhysical systemTorusElectronic mailing listCore dumpTerm (mathematics)Forcing (mathematics)Communications protocolFunctional (mathematics)Dependent and independent variablesProgramming languageOnline helpBlogLoginRelational databaseMultiplication signMereologyAuthenticationFlow separationWeb browserFormal languageCASE <Informatik>Hydraulic jumpComputer programmingIntegrated development environmentQuery languageControl flowRepository (publishing)Presentation of a groupSocial classSystem identificationDecision theoryObject (grammar)Computer clusterAutomatic differentiationCodeCartesian coordinate systemMultiplicationBitMoment (mathematics)FeedbackExpert systemSelf-organizationMonad (category theory)Mathematical optimizationAspect-oriented programmingFunctional programmingCombinational logicWeightComputer animation
Transcript: English(auto-generated)
Hello, welcome to the JavaScript Combinators talk. I'm Reg Brathwaite and I'm looking forward to spending the next hour talking about one of my favorite subjects with you, namely JavaScript Combinators.
Now one of the things I want to mention about it is that this is a topic that has some mathematical meaning, it has some functional programming meaning and it's very easy to get wrapped up in what these words mean and what these particular constructs
are in JavaScript, talk about what a decorator is or what composition is and so on. But as much as we're going to talk about those specific subjects and how to use these specific things, what I really want to talk about is decomposing programs and then
recomposing them in a way that we can give names to the individual responsibilities these things have and give names to the relationships between the various pieces. It's not just that this is what this particular construct is and what it does, but it's a particular purpose for using it. So the whole point of this talk where I really want to go is making responsibilities
and relationships explicit and that's something that actually goes far beyond functional programming or Combinators, but this happens to be an interesting way to go about exploring it. So off we go.
Now the first thing I want to talk about is decomposition, you know everyone I'm sure is very familiar with the idea of, you know, prefer composition over inheritance. People are always talking about the various ways that we compose programs. But typically what we do after we get something working is we decompose it and we put it
together in different ways, this is refactoring. We have an idea, we think about what the individual parts are so that we can do them one at a time. So we at least mentally spend as much time decomposing things as we do composing them. So I'd like to start there. Now when you have something big, a user, object in a typical application and you break
it into individual parts, its roles, its responsibilities and so on, what you want to do is you want to say which of these particular parts of it are important and give
those pieces names. That's a fundamental thing that we do. We break it into little pieces and we give them names. And each one of those individual pieces is supposed to have a responsibility, ideally if you follow the single responsibility principle one, but the world is not always ideal. But what we're always trying to do is be explicit about what the responsibilities
are of the individual pieces of a bigger program or unit. Decomposing something is a way of breaking it into the pieces so that we can name them all and give them their individual responsibilities. Now here's a piece of code I found on the web and a lot of people look at this and
they go, oh yes, call back hell and the multiple levels of indentation and so on. Coming from a LISP background, the multiple levels of indentation don't trouble me. But what I notice about it is it's one big sort of chunk of code and the individual pieces are not well named, but although you can look at it and see, okay, this part does a query and I can see a dot save in there somewhere and we seem to be assigning a user
to a current user, so you can sort of ferret out what the pieces are. A typical way to decompose it is to extract individual functions and then to have each individual piece call another piece by name.
This is a very common thing you'll find across all languages and all paradigms. We extract, once upon a time they were called subroutines, now they're functions. Sometimes in a more object oriented context we'll extract objects and use methods.
Now once we've extracted something, the business becomes, how do we compose it back, how do we put it back together? A moment ago we saw that it was put back together just by having functions call each other, but that's not the only way. When we compose them, besides just calling in line, we can also give the way in which
they're composed a name, and when we do that we make a relationship explicit. For example, if we recompose this using promises, you'll see now that we're using these methods instead of functions, but the difference between the function and the method is not important
here. The difference that is important is that the structure of the promise API is that we give a name to the way in which we associate these functions. It's a then, do this and then that. The important takeaway here is not method versus function, but rather that this particular
way of composing the functions is a way that names the relationship between the functions. So that when we decompose things, we're looking to do two different things. We're looking to decompose the individual entities that have responsibilities, and we're looking to decompose the relationships between them and pick out the important ones
and make sure that they are named, and obvious that we can communicate the way in which the individual pieces fit together. So when we look at it, decomposition is about entities. It's about finding out what are the sub-entities that belong to an entity, finding the right
way to put them together, and then when we put them back together, decomposition is about relationships. The way in which we compose software either highlights or hides the way in which the entities are related to each other. And I believe this to be true in every paradigm, whether it's object-oriented,
whether it's purely functional. So the way in which we put things together has the power to say these are the important relationships, these are not important, and the way in which we break them apart has the power to say these are the important entities you need to care about, and these particular ones are not.
And ideally we get those right, ideally. Now I'm going to take a moment and dive a little bit deeper into decomposition. Now, when I first put up that little snippet, I used what we might call the most obvious
form of decomposition, and I think it's only obvious because historically that's where we began with assemblers and so on, with subroutines, breaking something apart in that manner. So what I'd like to talk about is extracting functions. Now when you extract a function, and I'm saying a function here because today I happen
to be talking in a very functional programming way, but all these things map very directly over to the more object-oriented paradigms in JavaScript and other languages. When we extract a function, extract a method, we're reaching inside of something and pulling it out. So for that reason, I say that we are decomposing something from the inside out.
You're looking at the internals of it. It's an implementation technique. And for this particular case, we can look at a different example which will give us
a little bit more detail on doing that. So Pluck. How many people here are familiar that it shows up in a number of popular libraries, the Pluck function? No? Well, fantastic. In that case, we're going into some new territory.
Pluck takes a collection and it says, give me a particular property from each of the items in the collection. So if you have a bunch of users, you can pluck the names of the users, or you can pluck the occupations.
It's a form of mapping function. Now Pluck has an interface as well as an implementation. You see the implementation and also for a function, the interface is its signature, the arguments it consumes.
Now this particular one, there's only two arguments, the collection that it's going to operate on in the property. Those are its interface. Functions have very simple interfaces, typically. There's a saying by Alan J. Perlis that if you have a function that takes 10 arguments,
you've probably forgotten one. Typically, good functions have a clear responsibility and fewer arguments. And this particular one is very simple, just the two arguments. Now, if we want to manually decompose its interface as opposed to its implementation, what we want to do is we want to break apart the arguments it takes.
So here, I've created a function called PluckFrom. That takes a collection as an argument and gives you back a function that takes a property. So you can say if we want to pluck from destyle, then we can pass it a name. That allows us to take these two pieces, put them in different places, give them names.
For example, I didn't in this particular case, but we could say we could create a function called destyle plucker out of our pluck from destyle, put them in different places, store them. We've decomposed them to separate pieces that we can use in different ways.
We can go the other way, which I think is more flexible and more powerful when writing software in this particular case. And if you look at say underscore, underscore took the attitude of usually being sort of collection oriented.
So it's more of a pluck from type of library. And some of the other libraries that you'll find in JavaScript that work with functions like Rabda go the other way. They have a lot of things that are sort of the argument first. So they have things they may not name them pluck with, but they will have a lot of functions like this that are quite useful. In this particular case, we've broken the name part off,
extracting a name from a collection, and you pass it a collection. Now both of these two things have broken our pluck function into two different pieces, one of which is oriented around the thing that you're plucking, and the other is oriented around the thing that you are plucking from, the collection.
Now I wish I had a much more complicated and real world example, but everything has to fit on a slide, so I hope you're okay with my taking a simple function and breaking it into pieces to show the approach. Now here's the two dollar word, partial application.
We say that pluck from and pluck with both partially apply the pluck function. And it's good to know that word. First, because you'll see it elsewhere. And secondly, because we're going to see a connection. If you're reading about functional programming, talking to somebody about functional programming,
you're telling them about how fantastic it is, and they say, yeah, you know, I picked up this book, or I read this thing online, and they're talking about partial application and currying and this, that, and the other thing, and none of this seems very practical. The point here is to be able to connect that. You can say, oh yes, well, I can explain what partial application does, as do a number of blog posts and so on,
but I can tell you that the purpose of it is to be able to decompose a function so that we can give names to the individual parts. Aha! That connects the dots between the practice of what we're doing and these fancy theoretical concepts.
Now, the difference between decomposing when I extracted a bunch of functions from inside some code, which I called inside out, and decomposing when I used partial application to break the interface of a function into separate pieces is that the other one was inside out,
and as you can probably infer from the way this is going, when we decompose the interface, it's outside in. We're breaking an interface as opposed to implementation into individual entities. This is a very powerful idea. If you think about building a library,
if we want to scale this idea up, breaking little bits inside, you say, oh, I'm drawing this up and so on, you're working with the implementation and extracting methods and functions, that doesn't actually change the API of the library. But if you go and decompose the API, if you break the functions that are called into smaller pieces and so on,
that's actually changing the interface of the library for the pieces of code that are using it. You're actually changing the way in which people can use the library. So to me, this is a much more interesting form of decomposition and refactoring in a very practical way.
Now here's a term you'll see, I think often, a decorator is a very specialized form of function. It takes a function, it does something to it, gives you back another function that has been changed in some way, but it's essentially related to the original function.
Oh, fancy definition. How about that? Now, with our partial application that we had before, we're going to see how we can connect the dots
between partial application and decorators. Now, we have here pluck, and we can decompose that into pluck from, which we did a few moments ago, and then we can take in another step.
We can extract. You'll notice there's a pluck inside the pluck from function. We can extract that and bring it into the interface of some function that I don't have a name for, which we get in the middle, and then if I look at that and think about it for a while and give the things more general purpose names, we can see that we have a new function called left apply.
Left apply takes a function, and it takes an argument, and it gives you back a new function that will call the original function but supply the argument that you already had as the first argument and take something else you give it as the second argument.
Now, again, if you are new to functional programming, left application, it's like, what is the math of this? How does this connect? And we will connect the dots in a moment. If you're familiar with it, you'll say, oh, I know this. Isn't this the dot bind method of functions in JavaScript?
Absolutely. Dot bind in JavaScript performs left application. But the important thing is that the way in which we can use things like left apply is to decompose functions into parts. And that's what we're going to do.
Our pluck from we can build using left apply. We left apply pluck, and we take a collection, left apply it to the pluck, and what we end up with is a function that will take a collection and call pluck on it.
If we extract that same thing again and call left apply left apply on pluck, we'll get pluck from. And then crazily enough, we can do that one more time, and we get this hideous particular expression, left apply left apply left apply pluck, which I never put in production.
But it's interesting, because it actually looks like something else from functional programming. Who here knows what kind of spice this is? In London, really? Pardon?
These are curry powders. And in fact, currying, named after Haskell curry, is a very important part of functional programming and computer science. And left apply left apply left apply, in fact, is the curry function, although there's a much simpler way to write it, which is what we're going to do next.
There's nothing about that you need to know to get anything done in JavaScript. However, you can find everything you need to know in a book. If you're going to come to a conference, you ought to get something esoteric at least once a day, and hopefully this is it.
Now, we use left apply in order to build pluck from. And the purpose of doing that, as opposed to when we originally just formulated it simply, was to show that left apply is a general purpose operator for decomposing functions. There is a right apply that works in a similar way,
only instead of supplying the leftmost argument of a function, it supplies the right argument. And we can build pluck with using left apply and right apply, and we'll end up with this hideous expression at the bottom, left apply left apply right apply, in order to build pluck with.
And that we can simplify. I don't want to spend the whole day doing these combinator exercises because you can find them in all sorts of interesting books and blog posts. I star star, unfortunately JavaScript doesn't actually allow me to name a function with asterisks, is called the identity function twice removed,
and in JavaScript it's curry. Left apply is called the cardinal or C combinator. Sorry, not our left apply, but our left apply left apply right apply.
And with that, you can take any particular function like pluck, and turn it into something like pluck with. You can turn it into something that is applied to a collection, or applied to some other argument. Now, again, looking at these incredibly simple and very close to math
and not very close to the things we work with every day, or at least the things I work with every day, it looks very abstract. But again, the idea here is that we're taking any particular thing that used to be a bunch of code, call this, call this, pass it to this, and we're making relationships explicit and naming them.
Now, C is not a very good name. If you're not actually into combinatorial logic, C is terrible. But the principle that you could say, oh, the relationship between pluck with and pluck is that we're applying C to it, means that we're naming the relationship. And that's the thing to remember here, not the particular combinator. You can look that up in a book.
But to remember that by building something by calling a function, using a combinator, as opposed to building something by writing the code, we're giving a name to the relationship between the pieces. And that's the principle here. Here's a simpler example. Get is a very useful function I use all the time.
Actually, I use get with a lot more, but it's built out of get. Get is a function that takes an object and a property. Unfortunately, JavaScript does not permit us to actually program with the square braces like a function. It's like some magic built into the language. So if you want to actually do anything like that and use it as a function, you have to write a function
that basically applies square braces to things, and that's what get does. And get with is just like pluck became pluck with by applying the C combinator. Get with is very, very handy. You can call get with name, and that gives you a function that takes the name of a particular property.
That's very useful if you have to pass it something dynamic. And you can also build functions like name of. And again, you're naming a function. If you want to get the name of a particular object, you'll call the name of function. And if you say, well, what is this made out of, instead of again writing out a lot of code,
you're saying there's a relationship between the string name and name of, which is named explicitly with get with. And again, whether you memorize what get with is or not, the principle here again is that by writing functions that use functions to build other functions, you're naming the relationships between them.
And here's how it breaks down. We had a get function. We decomposed that with get with, which would be as opposed to get from. And then of all the different things you could get,
name of, you know, sort of specified it even further. That's what we do in software all the time. We do that with big systems and objects, and we can do that with small things like decomposing functions. Take this thing, break it down finer, finer, finer, and name the things that matter.
All we've done with these combinators, this fancy math, is the exact same thing, but with functions as opposed to with objects or subroutines. After this, this nuisance will cease. Here we have map. Map with is a particularly handy function,
which we make again using our C combinator. Getting the names of things is as simple as mapping with the name of function that we wrote two slides ago. Well, I wrote a week ago, but we looked at two slides ago. And again, what do we have here?
If we were working with these every day and this was at our fingertips, we would know that, oh, okay, I know what map with is, and names of is a relationship between name of that is named by using map with. Same principle, and again, we'll break it down to the same thing. There's map, map with, and names of, which are sort of continual decomposition of the original map function.
So I mentioned this before we started diving into these examples, and I will say it again. At some point, someone will say, oh, I read about a B combinator, C combinators.
Some specialists seem to name them after birds because of a popular book. Partial application, currying, you know, what is this stuff? What good is it? You know, outside of the fun of recreational mathematics, what's the important thing?
And again, the takeaway, you will say to them over your double espresso, ah, well, those are just ways of breaking functions into smaller pieces, decomposing them, and then putting them back together in a way that allows us to name the parts that are important to us or extract the parts we want to use more than once.
It's really that simple. There's an idea, and then there's the application of it. If we hold both in our minds, it's a very useful thing. Now, we've talked about decomposition, and of course we're talking about composition now. Let's start with the very simplest example of composition.
This is the compose function. It takes two functions, A and B, and gives you back a function where A calls what B returns after it calls C.
It's kind of a Russian doll function. And it's quite simple to use. You recall our distale, I think, if I were Dutch, something along those lines, artists.
And we can build PluckWith by composing MapWith and GetWith. It's kind of backwards. If we take any particular value, we pass it to GetWith, and whatever we get back from that, we pass to MapWith. And we can make names of by calling PluckWith on name, and we get this again.
I'm repeating all these things because when I was writing this, I was testing all the code, and hopefully I don't have any bugs. The compose, we saw when we broke things apart and we used things like GetWith and so on to name the entities, compose names the relationship between them
as opposed to writing a function and calling functions within it. In a very simple case like this, it's not that important because everything fits on one slide. But when you have functions that start to balloon, files that start to balloon, being able to name the relationship between parts becomes vital.
This simple thing here is really the whole talk. You could get up now and leave if you've absorbed this one slide. You can make a function by decomposing a function, and then you can put it back together, and along the way, you've chosen which things to name
and how to name the relationship between them. Everything from here is an elaboration of this. Now, I said that. I said it again. I said it another time. I'll keep saying it.
And one of the reasons is that when software starts to get non-trivial, because of cultural historical things, there tends to be an overemphasis on things that are nouns in the real world.
User, product, message, and an underemphasis on things that are verbs or adverbs or adjectives in the real world. I don't know if it's our software. I don't think it is. I think it's just somewhere we get taught
that an entity relationship diagram is the first thing you draw. You have to worry about what goes in database tables and so on, and we go along this way. And then quite often, you discover later when you're looking at some big code base somebody else has written, maybe you from two weeks ago and you don't remember and you're trying to tease things apart, it's the relationships, how the things connect that turn out to be important.
And because they're not named, you're like tracing code and going all the way through it. So, given that people are very good at naming things, becoming very good at naming the relationships between things can dramatically improve. Now, this is a claim that is not backed by a lot of data. This is what you would call an anecdote or an opinion. But in my opinion, you can dramatically improve the quality
of the code that you write and you work on by paying a little bit more attention to the thing that isn't kind of obvious and easy to pay attention to in this modern world. So, let's get into a bit more meat about that. And I'm going to spend more time giving you practical examples
of relationships between things because there aren't as many practical examples in the real world in my experience. Now, here's my fantastic thing that shows off all my knowledge of fine baking. We can mix, we can bake, and we can let it cool.
And when we wish to make bread, we take the ingredients, mix them, bake them, and cool them. This is the height of our technology in 2016. You're sitting in a room being told about this. How far our industry has come since my mother was a systems analyst in the late 1950s.
Now, here's an interesting decorator before. Part of a family of decorators that are really near and dear to me and that's why I enjoy talking about them and sharing my experience with them. Before takes some function that you wish to operate on,
call it the subject, and provides a decoration which is another function. And it gives you back a function that invokes the decoration and then invokes the function that you originally passed it. Before is a way of saying, I want to do this before that.
If you think back to our example with promises, this is a non-promise-oriented way of saying, do this before that. And what does it do? Names the relationship between the two. And how do we use it?
We have a simpler make bread, but we say, hey, before you do that, mix it. Many of you have seen by now that I'm giving a very simple presentation with a very simple structure so you can guess what the next thing we're going to look at. If we know how to make the time relationship
between two functions explicit by using before, the other thing we might use, after. Slightly more complicated because the typical behavioral contract is that it returns the value of the original thing you passed it
as opposed to the decoration. And I will say, we're trying to keep everything on a slide. If you look at real world examples of before and after decorators that you find in libraries or that you might want to write yourself, things like, how many people here work with Rails and Ruby?
One victim, very good. Two, form a club. There's a similar concept in Rails. However, if you return false from one of the decorators, before a decorator, it won't execute the rest so that you can write things like guards. There's a whole bunch you can go in different places. So these things can become more complicated,
but this is kind of the simplest thing that demonstrates the principle that we're looking for. Now, just like before, after is saying, these two things are related and this is the name of the relationship so it's quite obvious how it works.
Can't help it, back to decomposition. Original before took both the original function and a decoration. If we break that into two pieces, we can end up with mix before.
Mix before now allows us to name a piece. It's not just that we're doing something before, but our mix before function can take any other function and give you back something that mixes first. Now, mix before doesn't sound very handy unless you're actually writing some phenomenal baking software, but if I said we were writing something called authenticate before,
you could see the value of being able to have that and scatter it all through your code, or log after. And there we see cool after, and again we have combinators.
A combinator that makes a decorator. Now, you can see there's sort of some levels of abstraction. We had a function, we used a combinator that made a decorator. These are somewhat specialist terms, and if you find this really sort of engaging,
or if you're already into it, then you can find out more about these specific words. But the principle is still the same. There are functions that take other functions, they return functions, and what we use them for is to decompose the bigger pieces that we have into smaller pieces, and we're picking and choosing the names that matter to us
with the way we want to express our software. I mentioned earlier that things like before and after often have more complicated pieces so that we can use them as guards, catch exceptions, all sorts of funky things like that happen.
I don't want to get into those, but I do want to mention, in all honesty, that I left out something very important with the before and after combinators, and everything that we derive from them like before with and after with. The problem is that JavaScript is what I call a colored language.
There are multiple pieces of code that look the same but don't actually interoperate with each other. It's almost as if, and this isn't my metaphor, you go through your code and you could say, this is all blue code, and this is all red code, and this is all green code. For example, if you have code that uses callbacks,
it doesn't interoperate with code that uses promises. You have to have some sort of an adapter between them. They may look the same. Here's a function, here's an object, or whatever, but they're not actually the same. They're almost like written in separate languages that need an interface between them. And if you have code that is highly functional in the traditional manner, as I've written it here,
it will not operate very well with a specific set of code. And the code that I'm thinking of are methods. And the problem is all my functions before did nothing with this. They just ignored it.
So if you try to apply those to any methods, even though methods are functions in JavaScript, it turns out that they're a different color. They need you to specially handle this. So back to the drawing board, and here we have a new version of before and a new version of after.
You notice instead of calling functions, we're using the .apply method now. You notice the writing's a little bit smaller. It's harder to fit these onto the slide because we're adding a little bit of complexity, but it's worth it. Once we have these functions able to handle both methods
and ordinary functions, we can use them to decorate both methods and ordinary functions. That is very powerful because when we're writing classes, delegation, using prototypes, and we have methods,
we often have a problem where classes tend to get big and we're always trying to break them apart. We're trying to separate responsibilities. And being able to decorate methods allows us to separate responsibilities the same way we did with the toy functions that I showed earlier. We can decompose them and then recompose them in ways that name the relationship.
So let's do that. Here we go with our OO version of Bread. Now it's a class, and we're going to need a method for baking.
This is how we make our bread. And did you know that we can decorate classes in ES6? How many people know that? Yes, classes are expressions. And here's a way we can do it. Just barely squeezing everything.
And in fact, a production version of this is far more complicated because there's all sorts of little bits and pieces hanging off classes that will drive you insane when you're writing libraries for this. For example, you can declare a getter or a setter and a function like this ought to work with getters and setters as well as with methods.
You can declare things to be enumerable or not enumerable. And when you're decorating a method in a class, you should pay very close attention to whether the thing you're decorating is already enumerable or not enumerable so you don't break it and all sorts of stuff like that, which I am hand-waving over in this presentation. But what we are going to do is we're going to write a function called decorateMethodWith.
It takes a decorator. It takes a list of method names. Is everyone here familiar with the spread and gather features in ES6? Fantastic. Good-looking and experienced. I like that. It will give us back a function that takes a class, as I call it,
because class is usually a reserved word in almost every language. It will go through the various methods and it will take the method that it finds and define a new one, which it gets by calling the decorator on the original method body that it had. Using that, here are our new versions, our two new decorators,
beforeAll and afterAll, which we build by calling decorateMethodWith and giving it a little decorator. All this actually is already on the net,
but I will make sure to post the updated PDF of the slides. This particular presentation is actually written in Markdown. I'm using a product called DecSet. Everything is on my GitHub. You can actually go and get the actual code and copy and paste it if you're so interested.
Nevertheless, take pictures if you like. I understand that. Again, we're building a tower of pieces on top of pieces, both to fit into slides and also because that allows us to name the various relationships between them. Here's our better bread using this new technique.
We say beforeAll, we're going to invoke the mix method using a little invoker that I wrote. We did allow multiple things, but in this case, we only have one particular method that we care about, make.
Then afterAll, we're going to invoke the cool method. Again, we only care about make. The same thing, I use this exact same pattern in production now at PagerDuty, but it'll be much longer than this. It might be something like authenticate, and then there might be seven methods in a controller that are all decorated with the beforeAll.
Rails has this baked into ActiveController right now, the ability to write it before, that checks before any of the particular controller methods are made. One of the beautiful things about JavaScript is that you don't need to have an incredibly complicated library and make sure that any class you want to decorate with before functionality inherits from this library,
inherits from ActiveController or whatever, because classes are just entities, objects. The class expression is just an expression that returns a class, and you can write a function that takes that, manipulates it, and hands you back the class. Thus, here you see that we're just using functions to decorate it.
We don't need some magic syntax baked into the language in order to manipulate classes like this. And again, as nice as that is to decorate classes, it's not actually different from what we saw before. We're just taking functions, breaking them into pieces, naming the pieces we care about, and then putting them back together.
This business of having a decorator beforeAll or afterAll is a way of composing functionality and naming the way in which we're composing it so we see the relationships, as opposed to sticking an authenticator or a mix or whatever inside of a lot of functions.
Now, this is 2016, but JavaScript is not standing still. It continues to move forward. And in ES, who knows when, I'm not sure the terminology, ES later, ES next, ES soon, ES, it's in stage two.
We're going to get a new syntax, a Python-like syntax where you write at, and then you give it an expression that is a function, and then you can decorate a class. If you find that nicer, you can use a tool like Babel, and I think Traceur, I think, also supports this syntax,
and you can use that right now. I think it looks nice. It's a little easier than using the parentheses. But again, what does it do? It allows us to decompose responsibilities and name the relationships between them.
A little bit more complicated than that. In the era of ES5, all methods that we defined, we used the function keyword and used a function expression, and we assigned those functions to prototypes.
And because they were just functions, we could write decorators just like before that we saw earlier, and as long as they were the correct color, in other words, they properly respected this, they just worked. So you could decorate an individual method if you wanted to. There's no problem. With ES6, we now have compact method notation,
and that is the preferred way, especially in classes, because then it can respect super and a bunch of other bookkeeping it does behind the scenes. However, compact method notation does not allow us to decorate a method with a function. So, as a result, the upcoming, I don't know where this is,
but when the decorators you saw with classes come, we'll also get method decorators, and they will look like this. You'll be able to put them right on a particular method.
And again, what's happening? Decomposing the make into the separate pieces that we care about and then recomposing them using under-the-hood combinators, although you can just call them decorators. Now, if you're coming from zero to this, my goodness, 40 minutes,
what is that? I mean, the answer to that is Victory Boogie Woogie by Pete Mondrian, but we saw extracting functions, something I believe everybody here has done,
even if they didn't give it a particular name. We saw a promise interface. We saw how that composes things. We saw partial application. We saw how to extract a closed-over binding. We saw simple composition, decorators, class decorators,
method decorators coming from the next version. Now, I don't say this in a condescending way, as in don't worry about the details because you're confused. Every single one of us is approximately as equal in intelligence. Some of us have more experience with a particular thing than others.
When I say don't worry about the details, what I really mean is the specific application is either at your fingertips because you've been working with it or it's not, but it can get to your fingertips quickly. If you're motivated, if there's a value to you, and what is important about this is the value. And again, saying the same thing over again.
The value is being able to look at something and say, which of the important parts of this that have responsibilities I want to highlight when I write my code, being able to decompose it along those lines, and then say, what are the important relationships that I want to name so it's obvious how these things go together
and be able to recompose it along those lines. It's all the same whether we're talking about classes and methods or functions, or if we go outside of this particular presentation, which is mostly about a functional style of programming,
and look at OO, tomorrow I'm going to be talking about the command pattern, and if you're here, you're going to say, Reg is still talking about the same thing from yesterday, how to decompose things and how to name important responsibilities, but that'll be a much more object-oriented talk, but it's the same principle. We decompose things to make the responsibilities explicit,
and I'm sure by now you know the next thing I'm going to say. We recompose them in order to make the relationships explicit, and those are deep fundamentals in programming and software development.
I'm sure you've heard this quote before. It's by the late Phil Carlton, cash and validation and naming things, and when he says naming things is hard, someone just coming into the industry may say, oh, well, I've got this function, so finding the right name for the function is hard.
No. Naming things is hard because first you have to identify the right things to name. After you've identified the right things to name, naming things is easy, but the hard part is identifying the right things to name in order to communicate what this software does to someone who follows you, including yourself,
and that is something that goes across every single discipline we have. Just even the idea when people talk about, oh, we should have microservices versus this versus that, those are naming problems, right? Like, what are the individual pieces so I can say, oh, this does this?
It's all the same problem, naming things, and it's hard. Now, if naming entities is hard, what about naming relationships? Also hard. When you see a big ball of mud, you know, a big monolithic piece of code where all the pieces call each other,
this is a situation where naming the relationships between the pieces has become so hard that you can't even see them, much less name them. It is a very difficult problem to name the parts of software correctly,
and at no time in this presentation, I hope, have I told you that learning about combinators or a functional style of programming is going to make that problem go away. At no time, I hope, have I promised you a silver bullet. Now, just because it's a hard problem
doesn't mean it's not worth solving. Maybe that's what makes it really worth thinking about because it's a hard problem and because most people don't solve it well under time constraints. What I would say is that this style of thinking, which is exemplified when talking about functions
by combinators in a functional style of programming, by decomposing things using techniques like partial application or currying and then recomposing them with various types of compositional decorators, whether it's the compose function itself, befores, afters, and other things, is that combinators give us a language for naming things.
If I say partial application to you and you say, ah, I know what that's all about. It's all about binding these things so that I can name these two little things stuck together. Or if I say, oh, yes, I'm going to use, someone will come to you in OO style and tell you that they're going to use some before method advice.
You'll say, I know what that is. That's a way of composing things and naming the relationship between these two behaviors. It gives us a language. And I'm not a neuroscientist. I don't know if the Sapir-Horf hypothesis is correct or not, strong or weak, but fundamentally, I find it easier to work with things that I can name
than I do to sort of like make it up as I go along. And that is the value of learning techniques like this, to have these names and to make it easier for you to do this hard thing. So as I come close to the end, and I'm trying to leave a little space for Q&A
or to give you a jump on the Espresso lineup, I'd like to leave with an important thought. These sort of pure functional JavaScript, the good parts, all functions, few objects, stay away from the new keyword and so on, techniques,
go back to Scheme in the 1970s, maybe Lisp from the 60s, and they're very powerful. And it's totally ridiculous for people to invent new kinds of software without being aware of the history of things that smart and hardworking people have already researched.
So I think it is really important to learn these things. But that being said, I'm not into some sort of weird neo-trad thing where it's like, oh, everything should be like Scheme and we shouldn't do anything else. That doesn't make any sense.
It's not the 1960s or 70s anymore. Small talk was great. We should learn from it. Lisp was great. We should learn from it. Ruby was great. How's that? Can I use a was? We should learn from it. But we should respect what other people have done,
but don't follow them. We should seek what they sought. So as you go looking and so on, I hope that some part of what I've shown you here, you'll say, okay, I see where he's going with that, and then you'll find a better way, your own way. That's all I have for you today.
Thank you. If anyone has a question, we have a few minutes. As I said, if you want to get a jump on the washrooms or the espresso machine, I will not be in any way disappointed.
Questions? No? Pardon? Slash Ragonwald in GitHub, and then there's a presentations repository, and I will tweet that when I get a chance to sit down during the break.
And this particular one is called Combinator 6. And if you want a sneak peek, you can look at the repository for tomorrow's presentation. Yes, sir.
I like aspect-oriented programming. I do. I don't want to pass myself off as being a .NET expert, but I do have quite a bit of experience with aspect-oriented programming, and I'm somewhat pro.
Now, here I just wanted to stick with some basics, but one thing to, if you look at, if I back up, I don't know if you remember, but I talked about two different ways to mix before baking and then cool after baking. One of them decorated the entire class,
and the other one decorated the individual method. Now, those two things are very interesting because they highlight some of the considerations when looking at aspect-oriented programming. Aspect-oriented programming, for those who don't know, is a way of sort of separating that completely and saying, okay, all methods named index you don't need to be authenticated for, but all methods named get you do
across these classes and so on. So you can pull this kind of decoration or behavior aside from the sort of core behavior. And it does have a long pedigree. There's more modern terms, aspect-oriented programming, dating back to, I think his name was Bertrand Meyer, and Eiffel programming language brought a lot of this to the forefront, but if you look at things like the
common LISP meta-object protocol, they had the ability to, it evolved from something called LISP flavors, and flavors had this ability to put befores and afters associated with functions. But there's the fundamental dichotomy, that's probably a talk in itself, between decorating the class and saying these methods and decorating the individual methods,
is which thing are you trying to make easier? One thing is, I want to look at the class and I want to separate how to bake itself from these secondary responsibilities. Now, mixing before and cooling after is probably a terrible example of that, but authenticate and log might be a better example of that.
You want to keep that separate, and you want to have kind of like one thing which is responsible for knowing about authentication. Not the individual methods, but one thing. It's kind of like this is where we look at our authentication. This is its responsibility. Again, this is a decision about what to name. The other technique, decorating individual methods,
optimizes for, if I look at this method, let me see what it does. That helps you when you're debugging, for example. But the two different needs are actually intention. If you want to separate the responsibilities, a lot of times you want to glance at the method and you don't want to have to pierce through, okay, it authenticates and then it does this
and then it logs. You just want to see what's the core part of this method and you want to look at authentication separately. Our current languages make it difficult to optimize for both cases at the same time. Some other ways to go forward, like Smalltalk, for example, have browsers that are live in the environment
while the code is running and you can actually write queries and they had techniques going back to the 90s where you could get the answers to both of these questions. It's kind of like a relational database problem, isn't it? Show me all the methods that authenticate, or for this particular method, show me all the different decorations that it has.
So getting back to your question, what do I think about aspect-oriented programming, whether it be the specific things that .NET affords you or the general principle, I think it boils down to this thing that the talk was really about, being able to decide for your particular thing of what you're trying to express,
am I trying to separate the responsibility of something like authentication from the individual methods or am I trying to just decompose the individual methods in a way that I can see when looking at the method, but I'm not really trying to be able to go to one place and see which methods are authenticated. You have to make that decision and that will guide you as to whether to use it at all
or which parts of the application you use that technique as opposed to a different technique. I hope that answers it without too much hand-waving. Yes, sir?
I think all functions are curried automatically, aren't they? Yeah, there you go. And you don't have to worry about these multiple colors of functions in F-sharp.
As a matter of fact, if you want that functionality, you have to build it with monads in a properly functional language. Any other questions that anyone might have? Well, I will be around for the rest of the conference. Now that I've given my talk, I will stop avoiding people if you want to come up to me afterwards and say, hey, how about it?
I will ask one favor of everyone. Would you please give a very candid piece of feedback to the organizers about my talk? That will help me be a better speaker in the future and it will help them select the best possible speakers matched with the best possible audiences. So I'd appreciate that if you take a moment, if you have some thoughts about that, either to email them
or there's feedback or to use the correct card on your way out. There's a little colored card system. So please be...