summaryrefslogtreecommitdiffstats
path: root/2022/captions/emacsconf-2022-async--emacs-was-async-before-async-was-cool--michael-herstine--main.vtt
diff options
context:
space:
mode:
Diffstat (limited to '2022/captions/emacsconf-2022-async--emacs-was-async-before-async-was-cool--michael-herstine--main.vtt')
-rw-r--r--2022/captions/emacsconf-2022-async--emacs-was-async-before-async-was-cool--michael-herstine--main.vtt1505
1 files changed, 1505 insertions, 0 deletions
diff --git a/2022/captions/emacsconf-2022-async--emacs-was-async-before-async-was-cool--michael-herstine--main.vtt b/2022/captions/emacsconf-2022-async--emacs-was-async-before-async-was-cool--michael-herstine--main.vtt
new file mode 100644
index 00000000..eb25844e
--- /dev/null
+++ b/2022/captions/emacsconf-2022-async--emacs-was-async-before-async-was-cool--michael-herstine--main.vtt
@@ -0,0 +1,1505 @@
+WEBVTT
+
+1
+00:00:00.000 --> 00:00:02.720
+Hey everyone, I'm Michael
+
+2
+00:00:02.720 --> 00:00:04.480
+and I'm going to be talking to you today
+
+3
+00:00:04.480 --> 00:00:07.640
+about asynchronous programming in Emacs Lisp.
+
+4
+00:00:07.640 --> 00:00:10.360
+I'm located in the San Francisco Bay Area
+
+5
+00:00:10.360 --> 00:00:12.040
+where I'm a developer as well as
+
+6
+00:00:12.040 --> 00:00:14.160
+a long time Emacs user.
+
+7
+00:00:14.160 --> 00:00:18.760
+You may have heard of async or asynchronous programming.
+
+8
+00:00:18.760 --> 00:00:21.360
+The idea has been around for decades
+
+9
+00:00:21.360 --> 00:00:24.400
+but it first gained widespread attention in JavaScript
+
+10
+00:00:24.400 --> 00:00:26.720
+back in the aughts.
+
+11
+00:00:26.720 --> 00:00:29.680
+Then in the teens it gained tremendous popularity
+
+12
+00:00:29.680 --> 00:00:31.720
+in the DevOps world with Golang.
+
+13
+00:00:31.720 --> 00:00:33.800
+And just in the last few years
+
+14
+00:00:33.800 --> 00:00:37.880
+support for async programming has landed in Rust.
+
+15
+00:00:37.880 --> 00:00:40.080
+Well it can be done in Emacs as well
+
+16
+00:00:40.080 --> 00:00:42.040
+and this talk will demonstrate that
+
+17
+00:00:42.040 --> 00:00:44.600
+by walking you through a little problem
+
+18
+00:00:44.600 --> 00:00:47.200
+that I actually solved for myself.
+
+19
+00:00:47.200 --> 00:00:49.040
+Like a lot of these stories
+
+20
+00:00:49.040 --> 00:00:51.920
+it begins with scratching a personal itch.
+
+21
+00:00:51.920 --> 00:00:55.320
+In my case automating my music server.
+
+22
+00:00:55.320 --> 00:00:58.240
+I use something called the music player daemon locally
+
+23
+00:00:58.240 --> 00:01:00.240
+and as the name suggests
+
+24
+00:01:00.240 --> 00:01:03.560
+it just kind of hangs out in the background.
+
+25
+00:01:03.560 --> 00:01:08.040
+Reads music files and talks to assorted sound drivers.
+
+26
+00:01:08.040 --> 00:01:09.640
+In fact it is so focused on
+
+27
+00:01:09.640 --> 00:01:12.440
+that mission that it doesn't even offer a user interface.
+
+28
+00:01:12.440 --> 00:01:14.400
+Instead it serves an API
+
+29
+00:01:14.400 --> 00:01:16.120
+and invites application developers
+
+30
+00:01:16.120 --> 00:01:19.360
+to build clients on top of that API.
+
+31
+00:01:19.360 --> 00:01:22.200
+Okay so let's hop into a vterm
+
+32
+00:01:22.200 --> 00:01:25.080
+and I'd like to show you the MPD client I use
+
+33
+00:01:25.080 --> 00:01:26.600
+for my daily driver.
+
+34
+00:01:26.600 --> 00:01:29.520
+Something called ncmpcpp.
+
+35
+00:01:29.520 --> 00:01:31.800
+Doesn't exactly roll off the tongue
+
+36
+00:01:31.800 --> 00:01:33.720
+but I've got a playlist.
+
+37
+00:01:33.720 --> 00:01:36.560
+I can browse the file system.
+
+38
+00:01:36.560 --> 00:01:39.240
+Looks like I can search my music library.
+
+39
+00:01:39.240 --> 00:01:40.000
+Yada yada yada.
+
+40
+00:01:40.000 --> 00:01:42.600
+It's got all the basic features.
+
+41
+00:01:42.600 --> 00:01:44.640
+The point that I want to make is that
+
+42
+00:01:44.640 --> 00:01:51.920
+ncmpcpp is a completely independent project of MPD.
+
+43
+00:01:51.920 --> 00:01:53.720
+Separate and distinct.
+
+44
+00:01:53.720 --> 00:01:55.680
+It does all of its work
+
+45
+00:01:55.680 --> 00:01:57.200
+by simply communicating with
+
+46
+00:01:57.200 --> 00:02:01.400
+the music player daemon over the API.
+
+47
+00:02:01.400 --> 00:02:03.440
+Well I wanted to program to that API
+
+48
+00:02:03.440 --> 00:02:05.840
+only from within Emacs.
+
+49
+00:02:05.840 --> 00:02:09.520
+Now there are already Emacs MPD clients out there
+
+50
+00:02:09.520 --> 00:02:11.560
+but I didn't really want a full blown client.
+
+51
+00:02:11.560 --> 00:02:14.320
+I just wanted a few small tweaks
+
+52
+00:02:14.320 --> 00:02:16.320
+over my current configuration.
+
+53
+00:02:16.320 --> 00:02:19.280
+A command to skip to the next song.
+
+54
+00:02:19.280 --> 00:02:22.360
+Maybe shove the current track into the mode line.
+
+55
+00:02:22.360 --> 00:02:24.160
+Things like this.
+
+56
+00:02:24.160 --> 00:02:28.560
+I needed an elisp API that would let me do this.
+
+57
+00:02:28.560 --> 00:02:32.000
+Okay well let's get out of ncmpcpp
+
+58
+00:02:32.000 --> 00:02:37.560
+and let's get into a netcat session
+
+59
+00:02:37.560 --> 00:02:39.400
+with my local MPD server.
+
+60
+00:02:39.400 --> 00:02:43.840
+As you can see we get a welcome string.
+
+61
+00:02:43.840 --> 00:02:46.800
+So it is a server goes first protocol.
+
+62
+00:02:46.800 --> 00:02:49.640
+But after that it's a very familiar
+
+63
+00:02:49.640 --> 00:02:53.960
+text based request response oriented protocol.
+
+64
+00:02:53.960 --> 00:02:56.240
+I can ask for the volume.
+
+65
+00:02:56.240 --> 00:02:58.160
+I can ask for the status.
+
+66
+00:02:58.160 --> 00:03:06.000
+But in particular I wanted an asynchronous API.
+
+67
+00:03:06.000 --> 00:03:07.800
+If I issue a command like
+
+68
+00:03:07.800 --> 00:03:11.840
+find every track in my library
+
+69
+00:03:11.840 --> 00:03:15.360
+that's going to produce a lot of data
+
+70
+00:03:15.360 --> 00:03:18.920
+that's a human perceptible pause
+
+71
+00:03:18.920 --> 00:03:22.080
+as Emacs processes all the input.
+
+72
+00:03:22.080 --> 00:03:25.560
+What I wanted was a style of programming
+
+73
+00:03:25.560 --> 00:03:28.080
+where I could fire off my command
+
+74
+00:03:28.080 --> 00:03:31.560
+have the Emacs command loop keep working
+
+75
+00:03:31.560 --> 00:03:33.440
+and only invoke some callback
+
+76
+00:03:33.440 --> 00:03:35.280
+when there was data available.
+
+77
+00:03:35.280 --> 00:03:39.560
+Well Emacs is famously single threaded
+
+78
+00:03:39.560 --> 00:03:41.840
+so it shouldn't come as a surprise
+
+79
+00:03:41.840 --> 00:03:44.080
+that it offers a rich set of primitives
+
+80
+00:03:44.080 --> 00:03:46.720
+that enable the sort of network programming
+
+81
+00:03:46.720 --> 00:03:49.320
+that I wanted to do.
+
+82
+00:03:49.320 --> 00:03:50.760
+In particular it offers
+
+83
+00:03:50.760 --> 00:03:53.280
+a function called make network process.
+
+84
+00:03:53.280 --> 00:03:57.800
+Now this method offers a bewildering variety of options.
+
+85
+00:03:57.800 --> 00:03:59.320
+But at the heart of the matter
+
+86
+00:03:59.320 --> 00:04:01.040
+it opens a network connection
+
+87
+00:04:01.040 --> 00:04:03.120
+to some endpoint out there
+
+88
+00:04:03.120 --> 00:04:06.640
+and we can configure it to be non blocking.
+
+89
+00:04:06.640 --> 00:04:09.840
+It returns a handle that you can use to refer to
+
+90
+00:04:09.840 --> 00:04:14.880
+this network connection with other methods.
+
+91
+00:04:14.880 --> 00:04:17.760
+Other methods such as process and string
+
+92
+00:04:17.760 --> 00:04:19.600
+which as the name suggests
+
+93
+00:04:19.600 --> 00:04:21.960
+allows you to send textual data
+
+94
+00:04:21.960 --> 00:04:26.320
+to the remote endpoint of your network connection.
+
+95
+00:04:26.320 --> 00:04:29.400
+You can also use it with set process filter
+
+96
+00:04:29.400 --> 00:04:32.160
+which allows you to associate a callback
+
+97
+00:04:32.160 --> 00:04:33.240
+with your network connection.
+
+98
+00:04:33.240 --> 00:04:35.920
+That callback will be invoked
+
+99
+00:04:35.920 --> 00:04:40.480
+when there is data available
+
+100
+00:04:40.480 --> 00:04:41.960
+in the processes read buffer.
+
+101
+00:04:41.960 --> 00:04:44.960
+In other words in a request response oriented protocol
+
+102
+00:04:44.960 --> 00:04:47.800
+like that of MPD you open your socket
+
+103
+00:04:47.800 --> 00:04:50.960
+with make network process
+
+104
+00:04:50.960 --> 00:04:53.760
+send your request via process send string
+
+105
+00:04:53.760 --> 00:04:56.360
+and life will just continue in emacs
+
+106
+00:04:56.360 --> 00:04:57.560
+until some data shows up
+
+107
+00:04:57.560 --> 00:05:00.720
+in the processes read buffer
+
+108
+00:05:00.720 --> 00:05:05.200
+at which point your callback will be invoked.
+
+109
+00:05:05.200 --> 00:05:07.560
+It turns out this was enough
+
+110
+00:05:07.560 --> 00:05:12.280
+for a purpose built async runtime.
+
+111
+00:05:12.280 --> 00:05:14.800
+Let's work through the sequence of events
+
+112
+00:05:14.800 --> 00:05:16.480
+when opening a connection
+
+113
+00:05:16.480 --> 00:05:18.720
+and firing off a few commands in this style.
+
+114
+00:05:18.720 --> 00:05:22.120
+So let's imagine a library
+
+115
+00:05:22.120 --> 00:05:25.520
+that offers a connection object of some sort
+
+116
+00:05:25.520 --> 00:05:28.720
+a caller and an MPD server out on the network.
+
+117
+00:05:28.720 --> 00:05:31.880
+The caller will presumably get themselves
+
+118
+00:05:31.880 --> 00:05:34.760
+a connection object by invoking some sort of
+
+119
+00:05:34.760 --> 00:05:38.080
+connect method on our library.
+
+120
+00:05:38.080 --> 00:05:41.160
+We can handle this through make network process
+
+121
+00:05:41.160 --> 00:05:45.360
+but we're going to invoke make network process
+
+122
+00:05:45.360 --> 00:05:47.200
+with no weight equal to true
+
+123
+00:05:47.200 --> 00:05:48.520
+in other words asynchronously.
+
+124
+00:05:48.520 --> 00:05:52.240
+That means the method is going to return immediately.
+
+125
+00:05:52.240 --> 00:05:56.320
+We won't even know if the connection is up
+
+126
+00:05:56.320 --> 00:05:57.920
+let alone what the response would be.
+
+127
+00:05:57.920 --> 00:06:01.560
+This has some implications.
+
+128
+00:06:01.560 --> 00:06:05.280
+At this point we've returned control to the caller
+
+129
+00:06:05.280 --> 00:06:09.400
+the emacs event loop is proceeding quite happily
+
+130
+00:06:09.400 --> 00:06:11.320
+and so the caller is free
+
+131
+00:06:11.320 --> 00:06:14.920
+to start using our connection object.
+
+132
+00:06:14.920 --> 00:06:17.640
+They might say issue a status command.
+
+133
+00:06:17.640 --> 00:06:20.600
+Okay well in our library
+
+134
+00:06:20.600 --> 00:06:22.680
+we don't have a connection yet.
+
+135
+00:06:22.680 --> 00:06:25.920
+How on earth are we going to service this?
+
+136
+00:06:25.920 --> 00:06:29.440
+Well we can simply give ourselves a queue
+
+137
+00:06:29.440 --> 00:06:33.360
+and note down the fact that we owe a status command.
+
+138
+00:06:33.360 --> 00:06:35.560
+That's pretty quick.
+
+139
+00:06:35.560 --> 00:06:38.120
+We've now returned control back to our caller
+
+140
+00:06:38.120 --> 00:06:40.640
+and they are again free to issue more commands.
+
+141
+00:06:40.640 --> 00:06:41.840
+Maybe they issue a play command.
+
+142
+00:06:41.840 --> 00:06:45.160
+Okay well we're going to go deeper into debt
+
+143
+00:06:45.160 --> 00:06:48.160
+and note that we also owe a play command.
+
+144
+00:06:48.160 --> 00:06:56.160
+At some point in the indeterminate future MPDU
+
+145
+00:06:56.160 --> 00:06:57.320
+is the connection will get up
+
+146
+00:06:57.320 --> 00:07:03.000
+MPDU will allocate resources to track a new client.
+
+147
+00:07:03.000 --> 00:07:06.160
+They will write the welcome string into the socket
+
+148
+00:07:06.160 --> 00:07:07.920
+and those bytes are going to show up
+
+149
+00:07:07.920 --> 00:07:10.360
+in the emacs process read buffer
+
+150
+00:07:10.360 --> 00:07:13.160
+at which point our callback will be invoked.
+
+151
+00:07:13.160 --> 00:07:17.440
+We can parse the welcome string maybe
+
+152
+00:07:17.440 --> 00:07:19.240
+note the version that connection object
+
+153
+00:07:19.240 --> 00:07:20.400
+that might come in handy
+
+154
+00:07:20.400 --> 00:07:21.720
+but the key point is
+
+155
+00:07:21.720 --> 00:07:24.080
+our callback needs to take a look at the queue
+
+156
+00:07:24.080 --> 00:07:25.240
+and notice
+
+157
+00:07:25.240 --> 00:07:27.200
+oh we owe a status command
+
+158
+00:07:27.200 --> 00:07:29.880
+and so we'll invoke process and string
+
+159
+00:07:29.880 --> 00:07:32.280
+and send the status command down the pipe.
+
+160
+00:07:32.280 --> 00:07:36.760
+Again at some indeterminate time in the future
+
+161
+00:07:36.760 --> 00:07:38.600
+some bytes are going to show up
+
+162
+00:07:38.600 --> 00:07:41.200
+in our processes read buffer
+
+163
+00:07:41.200 --> 00:07:43.160
+and our callback will again be invoked.
+
+164
+00:07:43.160 --> 00:07:48.560
+We've got volume is 75 plus a lot of other stuff
+
+165
+00:07:48.560 --> 00:07:50.480
+and here we come to the next problem.
+
+166
+00:07:50.480 --> 00:07:54.440
+If our caller invoked status
+
+167
+00:07:54.440 --> 00:07:56.960
+they probably wanted to know about the status
+
+168
+00:07:56.960 --> 00:07:59.880
+so how shall we get them to them?
+
+169
+00:07:59.880 --> 00:08:03.040
+Well there's really not a lot of options at this point
+
+170
+00:08:03.040 --> 00:08:04.280
+except the callback.
+
+171
+00:08:04.280 --> 00:08:09.000
+Okay so change of plan our queue
+
+172
+00:08:09.000 --> 00:08:11.720
+is no longer a queue of commands
+
+173
+00:08:11.720 --> 00:08:13.840
+it's going to be a queue of commands
+
+174
+00:08:13.840 --> 00:08:15.880
+with associated callbacks.
+
+175
+00:08:15.880 --> 00:08:20.280
+We read the response off the socket
+
+176
+00:08:20.280 --> 00:08:23.440
+invoke our caller supplied callback
+
+177
+00:08:23.440 --> 00:08:26.080
+and then pop the queue.
+
+178
+00:08:26.080 --> 00:08:28.920
+At this point our callback
+
+179
+00:08:28.920 --> 00:08:32.160
+the library callback needs to know
+
+180
+00:08:32.160 --> 00:08:34.040
+that we still have a pending command
+
+181
+00:08:34.040 --> 00:08:35.720
+we fire that off down the pipe
+
+182
+00:08:35.720 --> 00:08:38.520
+at some indeterminate time in the future
+
+183
+00:08:38.520 --> 00:08:40.360
+we get a call we get a response
+
+184
+00:08:40.360 --> 00:08:42.640
+our callback is invoked
+
+185
+00:08:42.640 --> 00:08:45.720
+we invoke the caller supplied callback
+
+186
+00:08:45.720 --> 00:08:47.240
+and we pop the queue.
+
+187
+00:08:47.240 --> 00:08:53.760
+The structure of such a program
+
+188
+00:08:53.760 --> 00:08:55.800
+is best viewed as a finite state machine
+
+189
+00:08:55.800 --> 00:08:57.640
+and this is typically where you end up
+
+190
+00:08:57.640 --> 00:08:59.200
+in asynchronous programming at least
+
+191
+00:08:59.200 --> 00:09:03.360
+when you don't have a runtime grafted onto your program
+
+192
+00:09:03.360 --> 00:09:04.960
+the way you do with Golang
+
+193
+00:09:04.960 --> 00:09:08.240
+or when you don't have sort of extensive library support
+
+194
+00:09:08.240 --> 00:09:09.680
+the way you do with Rust.
+
+195
+00:09:09.680 --> 00:09:14.480
+Your data structure exists in one of these states
+
+196
+00:09:14.480 --> 00:09:15.440
+at any given time
+
+197
+00:09:15.440 --> 00:09:18.960
+and when input shows up on your file descriptor
+
+198
+00:09:18.960 --> 00:09:24.240
+you transition along one of these edges to a new state.
+
+199
+00:09:24.240 --> 00:09:28.160
+Cool so let's take a look at some of the code
+
+200
+00:09:28.160 --> 00:09:29.480
+that flows from this.
+
+201
+00:09:29.480 --> 00:09:32.240
+Okay let's hop over to an Emacs
+
+202
+00:09:32.240 --> 00:09:33.920
+and take a look at how we might code this up.
+
+203
+00:09:33.920 --> 00:09:38.360
+If you recall the sequence diagrams I shared
+
+204
+00:09:38.360 --> 00:09:40.120
+we're going to be scribbling down the command
+
+205
+00:09:40.120 --> 00:09:42.160
+and the callback that will be invoking
+
+206
+00:09:42.160 --> 00:09:43.240
+upon its completion.
+
+207
+00:09:43.240 --> 00:09:45.440
+So the first thing I did was give myself
+
+208
+00:09:45.440 --> 00:09:47.400
+a little command struct
+
+209
+00:09:47.400 --> 00:09:52.280
+with that I was able to define the connection object.
+
+210
+00:09:52.280 --> 00:09:56.280
+We're going to be storing the handle to the connection.
+
+211
+00:09:56.280 --> 00:09:59.400
+We're going to write down the protocol version
+
+212
+00:09:59.400 --> 00:10:02.000
+that we harvest from the welcome message
+
+213
+00:10:02.000 --> 00:10:03.560
+and of course we'll be recording
+
+214
+00:10:03.560 --> 00:10:05.760
+the command queue as well.
+
+215
+00:10:05.760 --> 00:10:08.640
+And so I gave myself a little connection object
+
+216
+00:10:08.640 --> 00:10:10.960
+with a connection struct
+
+217
+00:10:10.960 --> 00:10:12.240
+with those three attributes.
+
+218
+00:10:12.240 --> 00:10:15.000
+With the data model squared away
+
+219
+00:10:15.000 --> 00:10:17.840
+it was really pretty easy to code up
+
+220
+00:10:17.840 --> 00:10:21.160
+the connect implementation.
+
+221
+00:10:21.160 --> 00:10:24.880
+I'm deleting some details for exposition purposes
+
+222
+00:10:24.880 --> 00:10:29.520
+but in the event it's really not that more complex
+
+223
+00:10:29.520 --> 00:10:30.520
+than what you see here.
+
+224
+00:10:30.520 --> 00:10:32.840
+We're going to unpack the arguments,
+
+225
+00:10:32.840 --> 00:10:35.040
+figure out where the MPD server is
+
+226
+00:10:35.040 --> 00:10:37.280
+to which you would like us to connect.
+
+227
+00:10:37.280 --> 00:10:39.920
+We'll connect via make network process.
+
+228
+00:10:39.920 --> 00:10:42.640
+We'll associate a library defined callback
+
+229
+00:10:42.640 --> 00:10:45.920
+with that connection via set process filter.
+
+230
+00:10:45.920 --> 00:10:48.440
+Then we'll instantiate the connection object
+
+231
+00:10:48.440 --> 00:10:50.120
+and return it to the caller.
+
+232
+00:10:50.120 --> 00:10:53.800
+Once the caller has a connection object
+
+233
+00:10:53.800 --> 00:10:56.880
+they're free to send commands down that connection.
+
+234
+00:10:56.880 --> 00:10:59.120
+So what we're doing here
+
+235
+00:10:59.120 --> 00:11:02.320
+is simply instantiating a command object
+
+236
+00:11:02.320 --> 00:11:05.200
+on the basis of the caller supplied arguments
+
+237
+00:11:05.200 --> 00:11:06.640
+and appending it to the queue.
+
+238
+00:11:06.640 --> 00:11:07.920
+And then the last thing we do
+
+239
+00:11:07.920 --> 00:11:11.040
+and I've just indicated this with a comment
+
+240
+00:11:11.040 --> 00:11:12.040
+is we kick the queue.
+
+241
+00:11:12.040 --> 00:11:14.560
+This kind of goes back to
+
+242
+00:11:14.560 --> 00:11:18.200
+the state transition diagram I laid out earlier.
+
+243
+00:11:18.200 --> 00:11:22.680
+What this means is the logic for saying well
+
+244
+00:11:22.680 --> 00:11:24.280
+if we're waiting the completion
+
+245
+00:11:24.280 --> 00:11:25.480
+of a previously sent command
+
+246
+00:11:25.480 --> 00:11:27.280
+there's really not much more to be done.
+
+247
+00:11:27.280 --> 00:11:31.000
+We're just going to push this command onto the queue
+
+248
+00:11:31.000 --> 00:11:31.600
+and return.
+
+249
+00:11:31.600 --> 00:11:33.120
+On the other hand
+
+250
+00:11:33.120 --> 00:11:37.120
+if the queue was empty on entry to LMPD send
+
+251
+00:11:37.120 --> 00:11:39.160
+there's no reason not to just
+
+252
+00:11:39.160 --> 00:11:43.400
+immediately send the command.
+
+253
+00:11:43.400 --> 00:11:44.680
+And this is an example of
+
+254
+00:11:44.680 --> 00:11:46.520
+the sort of client side code
+
+255
+00:11:46.520 --> 00:11:48.080
+that results from this API.
+
+256
+00:11:48.080 --> 00:11:51.360
+So you can see here we are giving ourselves
+
+257
+00:11:51.360 --> 00:11:54.240
+a connection to the MPD server on the local host
+
+258
+00:11:54.240 --> 00:11:56.600
+and we're going to send the get volume command
+
+259
+00:11:56.600 --> 00:11:58.160
+down that connection.
+
+260
+00:11:58.160 --> 00:12:02.840
+And if that command completes and all is well
+
+261
+00:12:02.840 --> 00:12:05.360
+we'll just send a message to Emacs.
+
+262
+00:12:05.360 --> 00:12:07.800
+Unfortunately you can't see my mini buffer
+
+263
+00:12:07.800 --> 00:12:10.960
+so I'll hop over to the messages buffer
+
+264
+00:12:10.960 --> 00:12:12.720
+and there's our result.
+
+265
+00:12:12.720 --> 00:12:15.160
+The volume is 43.
+
+266
+00:12:15.160 --> 00:12:17.960
+Great I thought.
+
+267
+00:12:17.960 --> 00:12:22.520
+Simple clean responsive easy to code to.
+
+268
+00:12:22.520 --> 00:12:27.760
+That is unfortunately not the end of the story.
+
+269
+00:12:27.760 --> 00:12:32.320
+Let's continue this example a little bit.
+
+270
+00:12:32.320 --> 00:12:33.560
+Let's imagine that
+
+271
+00:12:33.560 --> 00:12:35.920
+if the volume comes back from the server
+
+272
+00:12:35.920 --> 00:12:37.360
+and it is less than 50
+
+273
+00:12:37.360 --> 00:12:38.600
+we would like to set it to 50.
+
+274
+00:12:38.600 --> 00:12:41.560
+So this is interesting
+
+275
+00:12:41.560 --> 00:12:43.200
+because we have two commands
+
+276
+00:12:43.200 --> 00:12:45.840
+and whether or not we send the second command
+
+277
+00:12:45.840 --> 00:12:46.840
+is going to depend on
+
+278
+00:12:46.840 --> 00:12:48.560
+the response we get from the first.
+
+279
+00:12:48.560 --> 00:12:51.640
+Okay I thought well that's fine
+
+280
+00:12:51.640 --> 00:12:55.080
+I can simply put that logic in the callback
+
+281
+00:12:55.080 --> 00:12:57.920
+that I specified for the get volume command.
+
+282
+00:12:57.920 --> 00:13:01.560
+So here we are we check the return code
+
+283
+00:13:01.560 --> 00:13:04.400
+we parse the volume we compare it to 50
+
+284
+00:13:04.400 --> 00:13:08.360
+and if it's less we just invoke LMPD send again
+
+285
+00:13:08.360 --> 00:13:10.800
+from the first command's callback.
+
+286
+00:13:10.800 --> 00:13:13.440
+Okay I could live with that
+
+287
+00:13:13.440 --> 00:13:15.520
+it's not the worst thing I've ever seen.
+
+288
+00:13:15.520 --> 00:13:19.400
+Let's extend this example a little further
+
+289
+00:13:19.400 --> 00:13:21.480
+and this is contrived but bear with me.
+
+290
+00:13:21.480 --> 00:13:25.480
+Let us suppose that if we do set the volume to 50
+
+291
+00:13:25.480 --> 00:13:27.800
+we'd like to get the volume one more time
+
+292
+00:13:27.800 --> 00:13:30.640
+just to make sure that our change took on the server.
+
+293
+00:13:30.640 --> 00:13:33.560
+Okay we can play the same game.
+
+294
+00:13:33.560 --> 00:13:37.280
+We will put that logic in the callback
+
+295
+00:13:37.280 --> 00:13:39.520
+that we specified for the set volume command.
+
+296
+00:13:39.520 --> 00:13:43.480
+And here we are we check the return code
+
+297
+00:13:43.480 --> 00:13:45.480
+we send a message to Emacs
+
+298
+00:13:45.480 --> 00:13:49.200
+we send the get volume command again
+
+299
+00:13:49.200 --> 00:13:51.080
+along with its own callback
+
+300
+00:13:51.080 --> 00:13:55.280
+and at this point I think you know I hope it's clear
+
+301
+00:13:55.280 --> 00:13:57.520
+the problem that is emerging
+
+302
+00:13:57.520 --> 00:14:01.360
+and if it's not yet let's let me note that so far
+
+303
+00:14:01.360 --> 00:14:03.000
+we're only handling the happy path
+
+304
+00:14:03.000 --> 00:14:04.520
+in each of these callbacks.
+
+305
+00:14:04.520 --> 00:14:06.840
+We really ought to do something about the error path
+
+306
+00:14:06.840 --> 00:14:10.120
+for purposes of illustration let's just say
+
+307
+00:14:10.120 --> 00:14:12.120
+we send a message to Emacs
+
+308
+00:14:12.120 --> 00:14:14.320
+that means it would look like this
+
+309
+00:14:14.320 --> 00:14:16.560
+and it's at this point
+
+310
+00:14:16.560 --> 00:14:19.400
+that I really think it's impossible to deny
+
+311
+00:14:19.400 --> 00:14:23.280
+that this API is actually not that easy to program to
+
+312
+00:14:23.280 --> 00:14:27.160
+and if there are any JavaScript devs watching
+
+313
+00:14:27.160 --> 00:14:28.840
+you're probably chuckling right now
+
+314
+00:14:28.840 --> 00:14:30.720
+because I have discovered for myself
+
+315
+00:14:30.720 --> 00:14:33.880
+what they call callback hell.
+
+316
+00:14:33.880 --> 00:14:36.040
+If you are returning
+
+317
+00:14:36.040 --> 00:14:40.160
+the results of asynchronous function invocations
+
+318
+00:14:40.160 --> 00:14:42.200
+to their caller via callbacks
+
+319
+00:14:42.200 --> 00:14:45.640
+you pretty much inevitably end up in this sort of
+
+320
+00:14:45.640 --> 00:14:48.040
+deeply nested sequence of callbacks
+
+321
+00:14:48.040 --> 00:14:49.880
+that is difficult to write difficult to read
+
+322
+00:14:49.880 --> 00:14:53.520
+and difficult to reason about.
+
+323
+00:14:53.520 --> 00:14:57.480
+And yet when I was stuck in this situation
+
+324
+00:14:57.480 --> 00:15:00.080
+it just seemed like it really shouldn't be this bad.
+
+325
+00:15:00.080 --> 00:15:05.320
+If I give myself this sort of tabular data structure
+
+326
+00:15:05.320 --> 00:15:10.160
+I felt that this expressed precisely the same logic
+
+327
+00:15:10.160 --> 00:15:11.960
+just in a much easier to read manner.
+
+328
+00:15:11.960 --> 00:15:15.840
+I could in my mind's eye
+
+329
+00:15:15.840 --> 00:15:19.720
+see the code for transforming this data structure
+
+330
+00:15:19.720 --> 00:15:21.040
+which is really just a list
+
+331
+00:15:21.040 --> 00:15:25.600
+into the code that you just saw in the previous slide
+
+332
+00:15:25.600 --> 00:15:29.440
+and really if Lisp is good at anything
+
+333
+00:15:29.440 --> 00:15:31.080
+it is list processing right
+
+334
+00:15:31.080 --> 00:15:33.080
+and it was really at this point
+
+335
+00:15:33.080 --> 00:15:35.240
+that a little bit of enlightenment dawned.
+
+336
+00:15:35.240 --> 00:15:40.800
+I learned that Lisp is homo iconic
+
+337
+00:15:40.800 --> 00:15:46.040
+which is just means that the language itself
+
+338
+00:15:46.040 --> 00:15:49.360
+is a data structure in that language.
+
+339
+00:15:49.360 --> 00:15:53.160
+Lisp code is after all just a list
+
+340
+00:15:53.160 --> 00:15:57.160
+and the power of Lisp macros
+
+341
+00:15:57.160 --> 00:15:59.760
+is taking that data structure
+
+342
+00:15:59.760 --> 00:16:02.400
+some data structure that you've defined
+
+343
+00:16:02.400 --> 00:16:04.640
+and doing exactly what I wanted to do
+
+344
+00:16:04.640 --> 00:16:07.520
+transforming it from one list into another
+
+345
+00:16:07.520 --> 00:16:11.080
+the destination list being Lisp code.
+
+346
+00:16:11.080 --> 00:16:16.000
+So I got busy and I coded up my first Lisp macro
+
+347
+00:16:16.000 --> 00:16:19.160
+which I called LMPD chain
+
+348
+00:16:19.160 --> 00:16:21.600
+and that lengthy list of you know
+
+349
+00:16:21.600 --> 00:16:24.200
+three or four nested callbacks
+
+350
+00:16:24.200 --> 00:16:25.920
+gets turned into this
+
+351
+00:16:25.920 --> 00:16:29.520
+which I hope you'll agree is much simpler
+
+352
+00:16:29.520 --> 00:16:32.240
+much easier to read much easier to reason about.
+
+353
+00:16:32.240 --> 00:16:36.000
+And if you're morbidly curious
+
+354
+00:16:36.000 --> 00:16:40.160
+you can you can expand your macros
+
+355
+00:16:40.160 --> 00:16:44.200
+and this invocation of LMPD chain expands to this.
+
+356
+00:16:44.200 --> 00:16:46.400
+So that's my story.
+
+357
+00:16:46.400 --> 00:16:50.840
+In all fairness I should note that
+
+358
+00:16:50.840 --> 00:16:55.160
+the MPD protocol has some subtleties and complexities
+
+359
+00:16:55.160 --> 00:16:56.880
+that I didn't really get into
+
+360
+00:16:56.880 --> 00:16:58.360
+both due to time constraints
+
+361
+00:16:58.360 --> 00:17:00.520
+and because they're not terribly relevant
+
+362
+00:17:00.520 --> 00:17:02.000
+to the points I wanted to touch on
+
+363
+00:17:02.000 --> 00:17:05.360
+I should also note that there's
+
+364
+00:17:05.360 --> 00:17:07.720
+a fair amount of work in the library itself
+
+365
+00:17:07.720 --> 00:17:11.240
+around accumulating partial responses
+
+366
+00:17:11.240 --> 00:17:12.560
+as they show up in the buffer
+
+367
+00:17:12.560 --> 00:17:16.120
+and dispatching them piecemeal to the caller
+
+368
+00:17:16.120 --> 00:17:19.720
+that was really too complex to get into here.
+
+369
+00:17:19.720 --> 00:17:22.360
+If you would like to see the code
+
+370
+00:17:22.360 --> 00:17:25.080
+it's available on GitHub as well as Melpa.
+
+371
+00:17:25.080 --> 00:17:29.200
+I'll be putting a version of this talk
+
+372
+00:17:29.200 --> 00:17:30.480
+on my personal site
+
+373
+00:17:30.480 --> 00:17:33.720
+and you can always reach out to me personally
+
+374
+00:17:33.720 --> 00:17:36.960
+I hang out on IRC as SPIF
+
+375
+00:17:36.960 --> 00:17:41.920
+or you can just email me as SPIF at P.O.Box dot com.
+
+376
+00:17:41.920 --> 00:17:47.880
+Thank you very much.