summaryrefslogtreecommitdiffstats
path: root/2022/captions/emacsconf-2022-async--emacs-was-async-before-async-was-cool--michael-herstine--main.vtt
blob: eb25844ed47b312e78b0250444c5f45a2395f3bf (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
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.