diff options
Diffstat (limited to '2021/captions')
-rw-r--r-- | 2021/captions/emacsconf-2021-form--old-mccarthy-had-a-form--ian-eure--main.vtt | 1282 | ||||
-rw-r--r-- | 2021/captions/form.md | 430 |
2 files changed, 1712 insertions, 0 deletions
diff --git a/2021/captions/emacsconf-2021-form--old-mccarthy-had-a-form--ian-eure--main.vtt b/2021/captions/emacsconf-2021-form--old-mccarthy-had-a-form--ian-eure--main.vtt new file mode 100644 index 00000000..4f95164f --- /dev/null +++ b/2021/captions/emacsconf-2021-form--old-mccarthy-had-a-form--ian-eure--main.vtt @@ -0,0 +1,1282 @@ +WEBVTT + +00:01.199 --> 00:00:02.320 +My name is Ian Eure, + +00:00:02.320 --> 00:00:03.199 +and welcome to my talk + +00:00:03.199 --> 00:00:05.120 +"Old McCarthy Had a Form". + +00:00:05.120 --> 00:00:05.759 +In this talk, + +00:00:05.759 --> 00:00:07.759 +I'm going to be discussing EIEIO, + +00:00:07.759 --> 00:00:09.920 +which is an Emacs Lisp implementation + +00:00:09.920 --> 00:00:12.320 +of the Common Lisp object system. + +00:12.320 --> 00:00:13.519 +CLOS is a way of writing + +00:13.519 --> 00:00:15.360 +object-oriented Common Lisp code, + +00:00:15.360 --> 00:00:17.920 +and with EIEIO you have much of that same + +00:17.920 --> 00:00:19.920 +power but inside Emacs. + +00:00:19.920 --> 00:00:21.359 +I'm going to be using those two names + +00:00:21.359 --> 00:00:22.988 +interchangeably throughout this talk, + +00:00:22.988 --> 00:00:26.640 +since they're nearly equivalent. + +00:26.640 --> 00:00:27.534 +You might wonder, + +00:00:27.534 --> 00:00:28.880 +"Why would I want to write + +00:00:28.880 --> 00:00:31.439 +object Emacs Lisp code?". + +00:00:31.439 --> 00:00:33.440 +I like it because I like writing + +00:00:33.440 --> 00:00:34.960 +in a functional programming style, + +00:00:34.960 --> 00:00:36.896 +or I like to do an imperative style + +00:00:36.896 --> 00:00:39.040 +that captures interactive key sequences + +00:00:39.040 --> 00:00:41.200 +that I might enter manually. + +00:41.200 --> 00:00:42.800 +Well, I think, different kinds of programs + +00:42.800 --> 00:00:45.120 +need different kind of programming paradigms, + +00:00:45.120 --> 00:00:47.760 +and sometimes OOP is the one that fits. + +00:00:47.760 --> 00:00:49.708 +Also, if you've done much OOP before, + +00:00:49.708 --> 00:00:50.655 +you might be surprised by + +00:00:50.655 --> 00:00:52.879 +how EIEIO works and the sorts of power + +00:00:52.879 --> 00:00:55.039 +that it brings to your programs. + +00:55.039 --> 00:00:58.480 +So, let's talk about that model now. + +00:58.480 --> 00:01:00.000 +Classes are pretty much what + +00:01:00.000 --> 00:01:01.120 +you would expect if you've done + +00:01:01.120 --> 00:01:02.879 +OOP programming before. + +01:02.879 --> 00:01:04.400 +In the CLOS model, + +00:01:04.400 --> 00:01:06.400 +they only have fields, + +00:01:06.400 --> 00:01:08.000 +they only encapsulate values, + +00:01:08.000 --> 00:01:10.720 +they don't have anything to do with methods. + +01:10.720 --> 00:01:13.040 +So, in this case, we have a base class for + +01:13.040 --> 00:01:15.040 +an EMMS player backend, + +00:01:15.040 --> 00:01:18.159 +and it has one field (a slot is what + +00:01:18.159 --> 00:01:20.000 +it's called in CLOS terminology), + +00:01:20.000 --> 00:01:22.720 +which indicates whether it's playing or not, + +00:01:22.720 --> 00:01:24.080 +and it's declared abstract, + +00:01:24.080 --> 00:01:25.439 +so you can't create an instance + +00:01:25.439 --> 00:01:27.040 +of an object based on this class, + +00:01:27.040 --> 00:01:29.280 +you can only extend it with another class, + +00:01:29.280 --> 00:01:31.119 +that's an EIEIO extension, + +00:01:31.119 --> 00:01:33.439 +but I think it's a pretty good one. + +01:33.439 --> 00:01:34.640 +You can also see there's a class + +00:01:34.640 --> 00:01:37.119 +that implements an mpv player back-end, + +00:01:37.119 --> 00:01:39.680 +and it extends the base class, + +00:01:39.680 --> 00:01:40.960 +it doesn't add any slots, + +00:01:40.960 --> 00:01:44.479 +and those get inherited from the base class. + +01:44.479 --> 00:01:45.936 +If you want these to do much more + +00:01:45.936 --> 00:01:46.960 +than encapsulate data, + +00:01:46.960 --> 00:01:48.880 +you need to start writing methods. + +00:01:48.880 --> 00:01:50.324 +The CLOS model is to have + +00:01:50.324 --> 00:01:51.439 +a generic function. + +00:01:51.439 --> 00:01:52.399 +A generic function is + +00:01:52.399 --> 00:01:53.680 +kind of like an interface, + +00:01:53.680 --> 00:01:55.600 +it's just a name and an argument list, + +01:55.600 --> 00:01:57.280 +and there's no implementation, + +00:01:57.280 --> 00:01:58.560 +you have to write a method + +00:01:58.560 --> 00:02:00.960 +in order to have an actual implementation. + +00:02:00.960 --> 00:02:02.880 +When you call the generic function, + +00:02:02.880 --> 00:02:04.960 +the system will do a dynamic dispatch + +00:02:04.960 --> 00:02:06.560 +to a method that matches based on + +00:02:06.560 --> 00:02:08.319 +its argument types and how the method + +00:02:08.319 --> 00:02:12.239 +has declared that it should be invoked. + +02:12.239 --> 00:02:14.239 +Here's an example of some methods + +00:02:14.239 --> 00:02:16.480 +for our mpv player backend, + +00:02:16.480 --> 00:02:19.599 +you can see that it'll play anything + +00:02:19.599 --> 00:02:21.200 +other than something + +00:02:21.200 --> 00:02:23.200 +with a keyword of `unplayable`, + +00:02:23.200 --> 00:02:25.328 +and it just has dummy start and stop methods + +00:02:25.328 --> 00:02:27.680 +that return "Started" and "Stopped" text. + +00:02:27.680 --> 00:02:29.599 +A method is just one implementation + +00:02:29.599 --> 00:02:30.552 +of a generic function, + +00:02:30.552 --> 00:02:32.640 +and you can have as many as you need. + +02:32.640 --> 00:02:33.920 +In order to determine + +00:02:33.920 --> 00:02:35.519 +which method gets dispatched + +00:02:35.519 --> 00:02:36.879 +when you call a generic function, + +00:02:36.879 --> 00:02:38.080 +they're specialized based on + +02:38.080 --> 00:02:39.360 +their argument type. + +00:02:39.360 --> 00:02:40.640 +In this case, you can see that + +00:02:40.640 --> 00:02:41.680 +first argument says + +00:02:41.680 --> 00:02:44.480 +`player talk/emms-player-mpv`, + +00:02:44.480 --> 00:02:46.239 +that means that if that first argument + +00:02:46.239 --> 00:02:48.480 +is an instance of the mpv player + +00:02:48.480 --> 00:02:50.080 +or a subclass of it, + +00:02:50.080 --> 00:02:52.000 +then those methods will be invoked, + +00:02:52.000 --> 00:02:53.560 +unless there's a more specific one + +00:02:53.560 --> 00:02:55.440 +based on that argument type. + +02:55.440 --> 00:02:56.656 +You don't have to define + +00:02:56.656 --> 00:02:57.760 +the generic functions. + +00:02:57.760 --> 00:02:59.040 +If you define a method, + +00:02:59.040 --> 00:03:00.451 +then it'll implicitly define + +00:03:00.451 --> 00:03:03.599 +the generic function for you. + +03:03.599 --> 00:03:05.440 +Specialization is really powerful. + +00:03:05.440 --> 00:03:06.939 +It lets the methods define + +00:03:06.939 --> 00:03:08.400 +how they get invoked + +00:03:08.400 --> 00:03:10.472 +If you've done much programming in Clojure, + +00:03:10.472 --> 00:03:12.959 +this sounds a little bit like multi-methods, + +00:03:12.959 --> 00:03:16.319 +but with multi-methods, only the main method, + +00:03:16.319 --> 00:03:18.000 +the equivalent of the generic function, + +00:03:18.000 --> 00:03:19.920 +can determine how they're dispatched. + +00:03:19.920 --> 00:03:21.519 +So, as the writer of an interface, + +00:03:21.519 --> 00:03:23.120 +you might not be able to foresee + +00:03:23.120 --> 00:03:25.519 +every way that someone who's implementing + +00:03:25.519 --> 00:03:26.959 +a version of that interface + +03:26.959 --> 00:03:28.400 +would like to dispatch. + +00:03:28.400 --> 00:03:29.920 +CLOS doesn't have that problem, + +00:03:29.920 --> 00:03:31.200 +you get to define your + +03:31.200 --> 00:03:34.080 +own invocation semantics. + +03:34.080 --> 00:03:35.360 +You're also not limited to + +00:03:35.360 --> 00:03:37.200 +dispatching based on the value + +00:03:37.200 --> 00:03:39.920 +being a subclass of an EIEIO type. + +00:03:39.920 --> 00:03:41.280 +You can dispatch based on + +03:41.280 --> 00:03:42.879 +a primitive type like integer, + +00:03:42.879 --> 00:03:45.360 +you can dispatch based on the value, + +03:45.360 --> 00:03:47.599 +you can dispatch on multiple arguments, + +03:47.599 --> 00:03:49.599 +and there's also a default dispatch + +00:03:49.599 --> 00:03:50.688 +that will get applied + +00:03:50.688 --> 00:03:53.200 +if there's no others that are defined. + +00:03:53.200 --> 00:03:54.319 +If you don't have a default, + +00:03:54.319 --> 00:03:55.439 +then you'll just get an error + +03:55.439 --> 00:03:56.480 +from the system, + +00:03:56.480 --> 00:03:57.439 +and if that doesn't cover it, + +00:03:57.439 --> 00:03:59.040 +you can even define your own. + +03:59.040 --> 00:04:00.239 +Definition is with the + +00:04:00.239 --> 00:04:01.760 +`cl-generic-generalizers`, + +00:04:01.760 --> 00:04:03.680 +which is itself a generic function. + +00:04:03.680 --> 00:04:05.680 +Much of CLOS is built in CLOS, + +00:04:05.680 --> 00:04:08.319 +which I think is really cool. + +04:08.319 --> 00:04:09.599 +In addition to all that, + +00:04:09.599 --> 00:04:12.319 +you have four different types of methods, + +04:12.319 --> 00:04:13.680 +and those are distinguished by + +00:04:13.680 --> 00:04:16.000 +what's called a qualifier. + +04:16.000 --> 00:04:18.400 +Every function can have methods + +00:04:18.400 --> 00:04:20.239 +that have all four different + +00:04:20.239 --> 00:04:21.280 +types of qualifiers, + +00:04:21.280 --> 00:04:22.960 +and based on your class inheritance, + +00:04:22.960 --> 00:04:25.680 +you might have multiple of each type. + +04:25.680 --> 00:04:26.800 +There's the primary method, + +00:04:26.800 --> 00:04:28.560 +which is equivalent to the method + +00:04:28.560 --> 00:04:29.919 +in any other OOP system, + +00:04:29.919 --> 00:04:32.160 +so we're not going to cover that too much. + +04:32.160 --> 00:04:33.759 +Then there's a `before` method. + +00:04:33.759 --> 00:04:35.600 +This is evaluated before + +00:04:35.600 --> 00:04:37.440 +the primary method for side effects, + +00:04:37.440 --> 00:04:40.080 +and its return value is discarded. + +00:04:40.080 --> 00:04:41.120 +There's an `after` method, + +00:04:41.120 --> 00:04:42.560 +which is the same but happens after + +00:04:42.560 --> 00:04:44.479 +the method has finished evaluating. + +04:44.479 --> 00:04:46.639 +And then there's an `around` method + +00:04:46.639 --> 00:04:49.199 +that happens around all the other three. + +04:49.199 --> 00:04:51.120 +And by using these types of methods + +00:04:51.120 --> 00:04:52.560 +and using class inheritance + +00:04:52.560 --> 00:04:54.560 +to compose them into your classes, + +00:04:54.560 --> 00:04:56.479 +you can add some really powerful + +00:04:56.479 --> 00:04:58.240 +mixin type functionality. + +00:04:58.240 --> 00:04:59.764 +You can use before and after + +00:04:59.764 --> 00:05:01.280 +to build things like logging, + +00:05:01.280 --> 00:05:02.479 +and you can use around + +00:05:02.479 --> 00:05:04.880 +to implement things like memoization. + +05:04.880 --> 00:05:06.720 +If you've done much Emacs Lisp programming, + +00:05:06.720 --> 00:05:08.160 +those before after and around + +00:05:08.160 --> 00:05:09.919 +might jog your memory because + +05:09.919 --> 00:05:11.440 +they're the same features you get + +00:05:11.440 --> 00:05:14.160 +with Emacs's built-in function advice. + +05:14.160 --> 00:05:15.680 +The thing with function advice is that + +05:15.680 --> 00:05:17.199 +it only works on functions + +00:05:17.199 --> 00:05:18.240 +in the global namespace, + +00:05:18.240 --> 00:05:20.360 +and there's no kind of conditionality, + +00:05:20.360 --> 00:05:21.840 +they always get dispatched + +00:05:21.840 --> 00:05:23.440 +when that function is invoked. + +05:23.440 --> 00:05:25.600 +The nice thing about the CLOS system is that + +00:05:25.600 --> 00:05:27.039 +whether they get invoked or not + +05:27.039 --> 00:05:28.872 +depends on whether they exist in + +00:05:28.872 --> 00:05:30.160 +the class hierarchy, + +00:05:30.160 --> 00:05:31.520 +so you can add them to your + +00:05:31.520 --> 00:05:32.880 +class hierarchy if you want + +00:05:32.880 --> 00:05:34.000 +that extra functionality + +00:05:34.000 --> 00:05:35.440 +like logging or memoization, + +00:05:35.440 --> 00:05:37.120 +and you can exclude it if you don't. + +00:05:37.120 --> 00:05:38.320 +I think that's really powerful + +05:38.320 --> 00:05:42.639 +and a very interesting way of doing it. + +05:42.639 --> 00:05:44.639 +It also supports multiple inheritance, + +05:44.639 --> 00:05:46.639 +which is the mechanism that you can use + +05:46.639 --> 00:05:48.560 +to compose all these different kinds of + +05:48.560 --> 00:05:50.479 +behaviors into a single object that does + +05:50.479 --> 00:05:52.240 +all the things that you want. + +00:05:52.240 --> 00:05:54.720 +Here's a quick example of a logger. + +00:05:54.720 --> 00:05:56.240 +So, you can see the class just has + +00:05:56.240 --> 00:05:58.319 +a single slot called `messages`, + +00:05:58.319 --> 00:05:59.840 +it has a `log` method + +00:05:59.840 --> 00:06:01.440 +that pushes a new message, + +00:06:01.440 --> 00:06:03.840 +which is a format string, into that, + +00:06:03.840 --> 00:06:05.520 +and then it will return them back out, + +00:06:05.520 --> 00:06:07.280 +or it'll just return the latest. + +06:07.280 --> 00:06:08.479 +And there's a simple example + +00:06:08.479 --> 00:06:09.600 +that shows it logging, + +00:06:09.600 --> 00:06:11.280 +and then shows it coming back out, + +00:06:11.280 --> 00:06:14.080 +pretty much what you would expect. + +06:14.080 --> 00:06:16.400 +Here's another class that adapts + +00:06:16.400 --> 00:06:19.039 +the `emms-player` to the `logger` class. + +00:06:19.039 --> 00:06:20.560 +It only extends the logger + +00:06:20.560 --> 00:06:22.400 +because it doesn't need any features + +00:06:22.400 --> 00:06:25.039 +of the `emms-player` class itself. + +00:06:25.039 --> 00:06:27.440 +It just implements methods that dispatch + +00:06:27.440 --> 00:06:30.240 +based on it being that logging player class, + +00:06:30.240 --> 00:06:31.759 +and you can see it logs whenever + +00:06:31.759 --> 00:06:34.240 +a track is started or stopped, + +00:06:34.240 --> 00:06:36.240 +and it also adds some track + +00:06:36.240 --> 00:06:37.520 +to tell you whether or not + +00:06:37.520 --> 00:06:38.560 +the track was playable, + +00:06:38.560 --> 00:06:41.199 +that is using the around method. + +00:06:41.199 --> 00:06:43.199 +So, you can see we have all three methods + +00:06:43.199 --> 00:06:45.280 +before, after, and around in this class, + +00:06:45.280 --> 00:06:48.160 +so you can see how those work. + +00:06:48.160 --> 00:06:49.440 +Then you need one more, + +00:06:49.440 --> 00:06:50.184 +which is the class + +00:06:50.184 --> 00:06:51.759 +that mixes it all together, + +00:06:51.759 --> 00:06:54.080 +So, that's the `logging-player-mpv`, + +00:06:54.080 --> 00:06:56.639 +and it extends both the `logging-player` class + +06:56.639 --> 00:06:59.680 +and the `emms-player-mpv` class. + +06:59.680 --> 00:07:01.440 +What's really interesting about this is + +07:01.440 --> 00:07:03.360 +that even though the logging player is + +07:03.360 --> 00:07:05.520 +part of the `emms-player` hierarchy, + +00:07:05.520 --> 00:07:06.472 +it doesn't depend on + +00:07:06.472 --> 00:07:08.240 +a specific implementation, + +00:07:08.240 --> 00:07:10.400 +so you can combine the two different + +00:07:10.400 --> 00:07:12.639 +classes that lets the logging class + +00:07:12.639 --> 00:07:13.919 +only care about logging, + +07:13.919 --> 00:07:15.440 +and the `emms-player` class + +00:07:15.440 --> 00:07:17.039 +only care about playing, + +00:07:17.039 --> 00:07:18.240 +and that is a really nice + +07:18.240 --> 00:07:19.599 +way of separating your concerns + +00:07:19.599 --> 00:07:21.440 +that I think is very powerful. + +07:21.440 --> 00:07:22.515 +Here's a quick example of + +00:07:22.515 --> 00:07:23.599 +just how that works, + +00:07:23.599 --> 00:07:25.199 +and you can see the `unplayable` + +07:25.199 --> 00:07:26.160 +track is not playable, + +00:07:26.160 --> 00:07:27.840 +and it gets logged as such, + +00:07:27.840 --> 00:07:29.360 +`foo` is playable, and you can see + +07:29.360 --> 00:07:31.120 +the logs in started and stopped. + +00:07:31.120 --> 00:07:32.560 +So, you can see it's having + +00:07:32.560 --> 00:07:34.000 +the side effects from those methods, + +00:07:34.000 --> 00:07:36.960 +and it's also returning + +00:07:36.960 --> 00:07:40.319 +the value off the player as well. + +07:40.319 --> 00:07:41.599 +I think this system has a bunch of + +07:41.599 --> 00:07:43.120 +really nice properties. + +07:43.120 --> 00:07:44.080 +First and foremost, + +00:07:44.080 --> 00:07:45.840 +it feels like a normal Lisp, + +00:07:45.840 --> 00:07:47.360 +all you're doing is calling functions, + +00:07:47.360 --> 00:07:49.840 +there's no magic involved. + +07:49.840 --> 00:07:51.919 +Also, you can use either or both of the + +07:51.919 --> 00:07:53.840 +classes or generic functions. + +00:07:53.840 --> 00:07:55.120 +If you only need to + +00:07:55.120 --> 00:07:56.960 +encapsulate data into a structure, + +00:07:56.960 --> 00:07:58.479 +then you can only use classes, + +07:58.479 --> 00:08:00.400 +you don't have to use generic functions. + +08:00.400 --> 00:08:02.080 +And if you only need dynamic dispatch, + +08:02.080 --> 00:08:03.068 +you can only implement + +00:08:03.068 --> 00:08:04.720 +a generic function and methods. + +00:08:04.720 --> 00:08:06.560 +You don't get forced into a model + +00:08:06.560 --> 00:08:08.000 +where you have to use both. + +00:08:08.000 --> 00:08:09.247 +You can mix and match for + +00:08:09.247 --> 00:08:10.800 +whatever needs your program has, + +00:08:10.800 --> 00:08:13.039 +which I think is really amazing. + +08:13.039 --> 00:08:15.440 +Any value can conform to an interface, + +08:15.440 --> 00:08:17.039 +meaning a generic function. + +00:08:17.039 --> 00:08:19.520 +So, you don't have to use those classes. + +00:08:19.520 --> 00:08:20.479 +You can even implement + +00:08:20.479 --> 00:08:22.240 +a generic function over `nil`, + +00:08:22.240 --> 00:08:23.599 +which gives you those really nice + +08:23.599 --> 00:08:24.800 +properties of Lisp, + +00:08:24.800 --> 00:08:26.460 +where you have nil-punning, you know, + +00:08:26.460 --> 00:08:28.800 +if you take the head of a nil list, + +00:08:28.800 --> 00:08:30.479 +then the output is `nil`, + +00:08:30.479 --> 00:08:31.283 +but you can do that + +00:08:31.283 --> 00:08:32.880 +with your object system too. + +00:08:32.880 --> 00:08:34.320 +And a really nice feature of that is + +08:34.320 --> 00:08:35.919 +that you have no possibility of + +00:08:35.919 --> 00:08:36.959 +null pointer exceptions + +00:08:36.959 --> 00:08:38.719 +like you do in other languages. + +00:08:38.719 --> 00:08:39.919 +They have a calling convention + +00:08:39.919 --> 00:08:42.880 +where you call object dot method, + +08:42.880 --> 00:08:45.600 +but in CLOS, you call a generic function, + +00:08:45.600 --> 00:08:47.279 +and you just give it some arguments. + +00:08:47.279 --> 00:08:48.959 +Typically, the first one is going to be + +00:08:48.959 --> 00:08:51.680 +an EIEIO class object, + +00:08:51.680 --> 00:08:53.200 +but it doesn't have to be, + +00:08:53.200 --> 00:08:54.640 +but because you're not calling that + +00:08:54.640 --> 00:08:55.519 +instance of an object, + +00:08:55.519 --> 00:08:57.279 +there's nothing to be nil in the first place, + +00:08:57.279 --> 00:08:58.320 +so there's no possibility of + +00:08:58.320 --> 00:09:00.080 +a nil pointer exception. + +09:00.080 --> 00:09:01.376 +And then the ability to + +00:09:01.376 --> 00:09:02.480 +have multiple inheritance + +00:09:02.480 --> 00:09:04.000 +and mix in all of these different + +00:09:04.000 --> 00:09:05.760 +functionalities into your final object + +00:09:05.760 --> 00:09:07.279 +is very powerful. + +09:07.279 --> 00:09:09.839 +Because you have multiple inheritance, + +00:09:09.839 --> 00:09:11.120 +your final object that + +00:09:11.120 --> 00:09:12.560 +composes all of those things + +00:09:12.560 --> 00:09:14.080 +is both a player and a logger, + +00:09:14.080 --> 00:09:15.600 +and it can be substituted into code + +00:09:15.600 --> 00:09:17.279 +that expects either of them. + +00:09:17.279 --> 00:09:19.040 +It's not an adapter class + +09:19.040 --> 00:09:21.360 +that only allows you to do one thing, + +00:09:21.360 --> 00:09:22.560 +it does both of them. + +00:09:22.560 --> 00:09:24.800 +I think that's amazing. + +09:24.800 --> 00:09:26.320 +So, here are some practical examples + +09:26.320 --> 00:09:27.387 +where I think maybe this + +00:09:27.387 --> 00:09:28.720 +could be a good idea. + +00:09:28.720 --> 00:09:30.399 +And I like to think about, + +09:30.399 --> 00:09:32.320 +"What is OOP actually good for?". + +00:09:32.320 --> 00:09:34.640 +I think it has three really amazing powers, + +09:34.640 --> 00:09:36.399 +encapsulation, abstraction, + +00:09:36.399 --> 00:09:37.279 +and extensibility, + +00:09:37.279 --> 00:09:39.200 +so let's look at those. + +09:39.200 --> 00:09:40.959 +Encapsulation is just keeping + +00:09:40.959 --> 00:09:42.480 +related data together. + +00:09:42.480 --> 00:09:43.680 +Here's an example from the + +09:43.680 --> 00:09:45.360 +transmission Torrent client. + +00:09:45.360 --> 00:09:46.399 +In order for it to work, + +00:09:46.399 --> 00:09:47.600 +it needs to have all four of + +09:47.600 --> 00:09:49.920 +these variables set consistently, + +00:09:49.920 --> 00:09:52.240 +but if you use the customization interface, + +09:52.240 --> 00:09:53.920 +they're kind of strewn all over the buffer + +00:09:53.920 --> 00:09:55.760 +because that shows them alphabetically + +00:09:55.760 --> 00:09:57.040 +by variable name instead of + +00:09:57.040 --> 00:09:59.920 +grouping them logically by function. + +09:59.920 --> 00:10:01.327 +You also have all these + +00:10:01.327 --> 00:10:02.480 +in the global namespace, + +00:10:02.480 --> 00:10:04.720 +so you need this disambiguation in front, + +00:10:04.720 --> 00:10:06.800 +you have to have a transmission prefix, + +00:10:06.800 --> 00:10:08.720 +so it's kind of ugly. + +10:08.720 --> 00:10:10.240 +An alternative example would be to + +10:10.240 --> 00:10:11.760 +encapsulate all of that + +00:10:11.760 --> 00:10:13.360 +in a single class. + +10:13.360 --> 00:10:16.160 +This has one slot for each of those values, + +00:10:16.160 --> 00:10:17.040 +except the username + +00:10:17.040 --> 00:10:18.000 +and password is broken out, + +00:10:18.000 --> 00:10:20.240 +there was only one in the previous example, + +00:10:20.240 --> 00:10:23.120 +but it works pretty much the same. + +10:23.120 --> 00:10:25.200 +The really neat thing about this is that + +10:25.200 --> 00:10:27.279 +the customization interface understands + +10:27.279 --> 00:10:29.920 +how to customize EIEIO objects, + +00:10:29.920 --> 00:10:32.640 +so you can set your custom variable + +00:10:32.640 --> 00:10:34.000 +to the value of an object, + +00:10:34.000 --> 00:10:35.760 +and in the customization interface, + +00:10:35.760 --> 00:10:37.040 +it shows you all of the fields, + +00:10:37.040 --> 00:10:38.399 +and it lets you edit the values + +00:10:38.399 --> 00:10:40.079 +of those slots directly. + +00:10:40.079 --> 00:10:41.760 +So, that keeps that logical grouping + +00:10:41.760 --> 00:10:44.800 +that I think makes things really easy to use. + +10:44.800 --> 00:10:46.160 +Another thing it's really good at is + +10:46.160 --> 00:10:48.268 +abstraction, and this is really core to + +00:10:48.268 --> 00:10:49.408 +a lot of what Emacs does + +00:10:49.408 --> 00:10:51.200 +because it runs on so many different systems, + +00:10:51.200 --> 00:10:53.308 +and it works with so many different + +00:10:53.308 --> 00:10:55.120 +kinds of similar tools. + +10:55.120 --> 00:10:56.109 +Here's an example from + +00:10:56.109 --> 00:10:58.079 +the built-in SQL implementation. + +00:10:58.079 --> 00:10:59.360 +This is the definition of + +00:10:59.360 --> 00:11:01.040 +the postgres backend, + +00:11:01.040 --> 00:11:02.160 +there's one of these for + +00:11:02.160 --> 00:11:04.000 +every supported database backend. + +00:11:04.000 --> 00:11:05.440 +And you can see, this is a pretty + +11:05.440 --> 00:11:08.480 +classic interface abstraction pattern. + +11:08.480 --> 00:11:09.680 +On the left-hand side, + +00:11:09.680 --> 00:11:10.880 +you have a symbol that's common + +00:11:10.880 --> 00:11:12.399 +among all the database backends, + +00:11:12.399 --> 00:11:14.160 +and the code that doesn't + +00:11:14.160 --> 00:11:16.240 +know about the implementation can use, + +00:11:16.240 --> 00:11:17.519 +no matter what implementation + +00:11:17.519 --> 00:11:19.040 +is being specified. + +00:11:19.040 --> 00:11:20.000 +On the right-hand side, + +00:11:20.000 --> 00:11:21.120 +you have the implementation + +00:11:21.120 --> 00:11:22.560 +specific values, + +00:11:22.560 --> 00:11:24.399 +in some cases these are just strings, + +00:11:24.399 --> 00:11:25.760 +or regexes, and in others + +00:11:25.760 --> 00:11:27.519 +those are actual functions. + +11:27.519 --> 00:11:29.440 +So, really this already is + +00:11:29.440 --> 00:11:30.720 +object orientation, + +00:11:30.720 --> 00:11:32.959 +it's just an ad-hoc system for it, + +00:11:32.959 --> 00:11:34.880 +but you don't have to use an ad-hoc system + +00:11:34.880 --> 00:11:35.519 +because there's this + +00:11:35.519 --> 00:11:38.000 +nice formal one instead. + +11:38.000 --> 00:11:38.880 +Another thing that it's + +00:11:38.880 --> 00:11:40.959 +really good at is extensibility, + +00:11:40.959 --> 00:11:42.160 +we saw some of that with + +00:11:42.160 --> 00:11:44.800 +the emms-player example earlier. + +00:11:44.800 --> 00:11:46.160 +But here's another thing I think + +00:11:46.160 --> 00:11:48.720 +it would be interesting to explore. + +11:48.720 --> 00:11:51.279 +Emacs has this idea of derived modes + +11:51.279 --> 00:11:52.639 +where you have a mode that's based on + +11:52.639 --> 00:11:54.639 +another, and that's a pretty clear + +11:54.639 --> 00:11:57.040 +inheritance pattern straight out of OOP + +11:57.040 --> 00:11:58.560 +as far as I'm concerned. + +00:11:58.560 --> 00:12:00.079 +What would it look like + +00:12:00.079 --> 00:12:02.959 +if major modes were EIEIO classes, + +00:12:02.959 --> 00:12:04.800 +and you could extend your mode + +12:04.800 --> 00:12:06.399 +by extending the class. + +00:12:06.399 --> 00:12:08.240 +I think that's a really interesting idea, + +00:12:08.240 --> 00:12:10.880 +and I'd like to explore that more. + +12:10.880 --> 00:12:14.079 +In conclusion, I think EIEIO is amazing, + +12:14.079 --> 00:12:16.079 +and I had no idea that such a powerful + +12:16.079 --> 00:12:18.079 +object orientation system + +00:12:18.079 --> 00:12:20.160 +was available in the Emacs. + +12:20.160 --> 00:12:21.519 +My goal with this talk + +00:12:21.519 --> 00:12:23.519 +is for anyone who writes Emacs Lisp, + +00:12:23.519 --> 00:12:25.360 +to look at these classes of problems, + +00:12:25.360 --> 00:12:27.360 +encapsulation, abstraction, + +00:12:27.360 --> 00:12:28.639 +and extensibility, + +00:12:28.639 --> 00:12:29.600 +and if you run into + +00:12:29.600 --> 00:12:31.279 +those problems in your code, + +12:31.279 --> 00:12:33.279 +instead of immediately reaching + +00:12:33.279 --> 00:12:34.959 +and building your own system, + +00:12:34.959 --> 00:12:35.760 +I want you to think: + +00:12:35.760 --> 00:12:37.279 +"Oh there's a thing for that, + +00:12:37.279 --> 00:12:39.040 +and I can just use it." + +12:39.040 --> 00:12:40.560 +That's my talk, thanks. + +00:12:40.560 --> 00:12:41.560 +Hack on! + +00:12:41.560 --> 00:12:43.880 +[captions by bhavin192 (Bhavin Gandhi)] diff --git a/2021/captions/form.md b/2021/captions/form.md new file mode 100644 index 00000000..76984b28 --- /dev/null +++ b/2021/captions/form.md @@ -0,0 +1,430 @@ +<a name="transcript"></a> +# Transcript + +[[!template text="My name is Ian Eure," start="00:00:01.199" video="mainVideo" id=subtitle]] +[[!template text="and welcome to my talk" start="00:00:02.320" video="mainVideo" id=subtitle]] +[[!template text=""Old McCarthy Had a Form"." start="00:00:03.199" video="mainVideo" id=subtitle]] +[[!template text="In this talk," start="00:00:05.120" video="mainVideo" id=subtitle]] +[[!template text="I'm going to be discussing EIEIO," start="00:00:05.759" video="mainVideo" id=subtitle]] +[[!template text="which is an Emacs Lisp implementation" start="00:00:07.759" video="mainVideo" id=subtitle]] +[[!template text="of the Common Lisp object system." start="00:00:09.920" video="mainVideo" id=subtitle]] +[[!template text="CLOS is a way of writing" start="00:00:12.320" video="mainVideo" id=subtitle]] +[[!template text="object-oriented Common Lisp code," start="00:00:13.519" video="mainVideo" id=subtitle]] +[[!template text="and with EIEIO you have much of that same" start="00:00:15.360" video="mainVideo" id=subtitle]] +[[!template text="power but inside Emacs." start="00:00:17.920" video="mainVideo" id=subtitle]] +[[!template text="I'm going to be using those two names" start="00:00:19.920" video="mainVideo" id=subtitle]] +[[!template text="interchangeably throughout this talk," start="00:00:21.359" video="mainVideo" id=subtitle]] +[[!template text="since they're nearly equivalent." start="00:00:22.988" video="mainVideo" id=subtitle]] +[[!template text="You might wonder," start="00:00:26.640" video="mainVideo" id=subtitle]] +[[!template text=""Why would I want to write" start="00:00:27.534" video="mainVideo" id=subtitle]] +[[!template text="object Emacs Lisp code?"." start="00:00:28.880" video="mainVideo" id=subtitle]] +[[!template text="I like it because I like writing" start="00:00:31.439" video="mainVideo" id=subtitle]] +[[!template text="in a functional programming style," start="00:00:33.440" video="mainVideo" id=subtitle]] +[[!template text="or I like to do an imperative style" start="00:00:34.960" video="mainVideo" id=subtitle]] +[[!template text="that captures interactive key sequences" start="00:00:36.896" video="mainVideo" id=subtitle]] +[[!template text="that I might enter manually." start="00:00:39.040" video="mainVideo" id=subtitle]] +[[!template text="Well, I think, different kinds of programs" start="00:00:41.200" video="mainVideo" id=subtitle]] +[[!template text="need different kind of programming paradigms," start="00:00:42.800" video="mainVideo" id=subtitle]] +[[!template text="and sometimes OOP is the one that fits." start="00:00:45.120" video="mainVideo" id=subtitle]] +[[!template text="Also, if you've done much OOP before," start="00:00:47.760" video="mainVideo" id=subtitle]] +[[!template text="you might be surprised by" start="00:00:49.708" video="mainVideo" id=subtitle]] +[[!template text="how EIEIO works and the sorts of power" start="00:00:50.655" video="mainVideo" id=subtitle]] +[[!template text="that it brings to your programs." start="00:00:52.879" video="mainVideo" id=subtitle]] +[[!template text="So, let's talk about that model now." start="00:00:55.039" video="mainVideo" id=subtitle]] +[[!template text="Classes are pretty much what" start="00:00:58.480" video="mainVideo" id=subtitle]] +[[!template text="you would expect if you've done" start="00:01:00.000" video="mainVideo" id=subtitle]] +[[!template text="OOP programming before." start="00:01:01.120" video="mainVideo" id=subtitle]] +[[!template text="In the CLOS model," start="00:01:02.879" video="mainVideo" id=subtitle]] +[[!template text="they only have fields," start="00:01:04.400" video="mainVideo" id=subtitle]] +[[!template text="they only encapsulate values," start="00:01:06.400" video="mainVideo" id=subtitle]] +[[!template text="they don't have anything to do with methods." start="00:01:08.000" video="mainVideo" id=subtitle]] +[[!template text="So, in this case, we have a base class for" start="00:01:10.720" video="mainVideo" id=subtitle]] +[[!template text="an EMMS player backend," start="00:01:13.040" video="mainVideo" id=subtitle]] +[[!template text="and it has one field (a slot is what" start="00:01:15.040" video="mainVideo" id=subtitle]] +[[!template text="it's called in CLOS terminology)," start="00:01:18.159" video="mainVideo" id=subtitle]] +[[!template text="which indicates whether it's playing or not," start="00:01:20.000" video="mainVideo" id=subtitle]] +[[!template text="and it's declared abstract," start="00:01:22.720" video="mainVideo" id=subtitle]] +[[!template text="so you can't create an instance" start="00:01:24.080" video="mainVideo" id=subtitle]] +[[!template text="of an object based on this class," start="00:01:25.439" video="mainVideo" id=subtitle]] +[[!template text="you can only extend it with another class," start="00:01:27.040" video="mainVideo" id=subtitle]] +[[!template text="that's an EIEIO extension," start="00:01:29.280" video="mainVideo" id=subtitle]] +[[!template text="but I think it's a pretty good one." start="00:01:31.119" video="mainVideo" id=subtitle]] +[[!template text="You can also see there's a class" start="00:01:33.439" video="mainVideo" id=subtitle]] +[[!template text="that implements an mpv player back-end," start="00:01:34.640" video="mainVideo" id=subtitle]] +[[!template text="and it extends the base class," start="00:01:37.119" video="mainVideo" id=subtitle]] +[[!template text="it doesn't add any slots," start="00:01:39.680" video="mainVideo" id=subtitle]] +[[!template text="and those get inherited from the base class." start="00:01:40.960" video="mainVideo" id=subtitle]] +[[!template text="If you want these to do much more" start="00:01:44.479" video="mainVideo" id=subtitle]] +[[!template text="than encapsulate data," start="00:01:45.936" video="mainVideo" id=subtitle]] +[[!template text="you need to start writing methods." start="00:01:46.960" video="mainVideo" id=subtitle]] +[[!template text="The CLOS model is to have" start="00:01:48.880" video="mainVideo" id=subtitle]] +[[!template text="a generic function." start="00:01:50.324" video="mainVideo" id=subtitle]] +[[!template text="A generic function is" start="00:01:51.439" video="mainVideo" id=subtitle]] +[[!template text="kind of like an interface," start="00:01:52.399" video="mainVideo" id=subtitle]] +[[!template text="it's just a name and an argument list," start="00:01:53.680" video="mainVideo" id=subtitle]] +[[!template text="and there's no implementation," start="00:01:55.600" video="mainVideo" id=subtitle]] +[[!template text="you have to write a method" start="00:01:57.280" video="mainVideo" id=subtitle]] +[[!template text="in order to have an actual implementation." start="00:01:58.560" video="mainVideo" id=subtitle]] +[[!template text="When you call the generic function," start="00:02:00.960" video="mainVideo" id=subtitle]] +[[!template text="the system will do a dynamic dispatch" start="00:02:02.880" video="mainVideo" id=subtitle]] +[[!template text="to a method that matches based on" start="00:02:04.960" video="mainVideo" id=subtitle]] +[[!template text="its argument types and how the method" start="00:02:06.560" video="mainVideo" id=subtitle]] +[[!template text="has declared that it should be invoked." start="00:02:08.319" video="mainVideo" id=subtitle]] +[[!template text="Here's an example of some methods" start="00:02:12.239" video="mainVideo" id=subtitle]] +[[!template text="for our mpv player backend," start="00:02:14.239" video="mainVideo" id=subtitle]] +[[!template text="you can see that it'll play anything" start="00:02:16.480" video="mainVideo" id=subtitle]] +[[!template text="other than something" start="00:02:19.599" video="mainVideo" id=subtitle]] +[[!template text="with a keyword of `unplayable`," start="00:02:21.200" video="mainVideo" id=subtitle]] +[[!template text="and it just has dummy start and stop methods" start="00:02:23.200" video="mainVideo" id=subtitle]] +[[!template text="that return "Started" and "Stopped" text." start="00:02:25.328" video="mainVideo" id=subtitle]] +[[!template text="A method is just one implementation" start="00:02:27.680" video="mainVideo" id=subtitle]] +[[!template text="of a generic function," start="00:02:29.599" video="mainVideo" id=subtitle]] +[[!template text="and you can have as many as you need." start="00:02:30.552" video="mainVideo" id=subtitle]] +[[!template text="In order to determine" start="00:02:32.640" video="mainVideo" id=subtitle]] +[[!template text="which method gets dispatched" start="00:02:33.920" video="mainVideo" id=subtitle]] +[[!template text="when you call a generic function," start="00:02:35.519" video="mainVideo" id=subtitle]] +[[!template text="they're specialized based on" start="00:02:36.879" video="mainVideo" id=subtitle]] +[[!template text="their argument type." start="00:02:38.080" video="mainVideo" id=subtitle]] +[[!template text="In this case, you can see that" start="00:02:39.360" video="mainVideo" id=subtitle]] +[[!template text="first argument says" start="00:02:40.640" video="mainVideo" id=subtitle]] +[[!template text="`player talk/emms-player-mpv`," start="00:02:41.680" video="mainVideo" id=subtitle]] +[[!template text="that means that if that first argument" start="00:02:44.480" video="mainVideo" id=subtitle]] +[[!template text="is an instance of the mpv player" start="00:02:46.239" video="mainVideo" id=subtitle]] +[[!template text="or a subclass of it," start="00:02:48.480" video="mainVideo" id=subtitle]] +[[!template text="then those methods will be invoked," start="00:02:50.080" video="mainVideo" id=subtitle]] +[[!template text="unless there's a more specific one" start="00:02:52.000" video="mainVideo" id=subtitle]] +[[!template text="based on that argument type." start="00:02:53.560" video="mainVideo" id=subtitle]] +[[!template text="You don't have to define" start="00:02:55.440" video="mainVideo" id=subtitle]] +[[!template text="the generic functions." start="00:02:56.656" video="mainVideo" id=subtitle]] +[[!template text="If you define a method," start="00:02:57.760" video="mainVideo" id=subtitle]] +[[!template text="then it'll implicitly define" start="00:02:59.040" video="mainVideo" id=subtitle]] +[[!template text="the generic function for you." start="00:03:00.451" video="mainVideo" id=subtitle]] +[[!template text="Specialization is really powerful." start="00:03:03.599" video="mainVideo" id=subtitle]] +[[!template text="It lets the methods define" start="00:03:05.440" video="mainVideo" id=subtitle]] +[[!template text="how they get invoked" start="00:03:06.939" video="mainVideo" id=subtitle]] +[[!template text="If you've done much programming in Clojure," start="00:03:08.400" video="mainVideo" id=subtitle]] +[[!template text="this sounds a little bit like multi-methods," start="00:03:10.472" video="mainVideo" id=subtitle]] +[[!template text="but with multi-methods, only the main method," start="00:03:12.959" video="mainVideo" id=subtitle]] +[[!template text="the equivalent of the generic function," start="00:03:16.319" video="mainVideo" id=subtitle]] +[[!template text="can determine how they're dispatched." start="00:03:18.000" video="mainVideo" id=subtitle]] +[[!template text="So, as the writer of an interface," start="00:03:19.920" video="mainVideo" id=subtitle]] +[[!template text="you might not be able to foresee" start="00:03:21.519" video="mainVideo" id=subtitle]] +[[!template text="every way that someone who's implementing" start="00:03:23.120" video="mainVideo" id=subtitle]] +[[!template text="a version of that interface" start="00:03:25.519" video="mainVideo" id=subtitle]] +[[!template text="would like to dispatch." start="00:03:26.959" video="mainVideo" id=subtitle]] +[[!template text="CLOS doesn't have that problem," start="00:03:28.400" video="mainVideo" id=subtitle]] +[[!template text="you get to define your" start="00:03:29.920" video="mainVideo" id=subtitle]] +[[!template text="own invocation semantics." start="00:03:31.200" video="mainVideo" id=subtitle]] +[[!template text="You're also not limited to" start="00:03:34.080" video="mainVideo" id=subtitle]] +[[!template text="dispatching based on the value" start="00:03:35.360" video="mainVideo" id=subtitle]] +[[!template text="being a subclass of an EIEIO type." start="00:03:37.200" video="mainVideo" id=subtitle]] +[[!template text="You can dispatch based on" start="00:03:39.920" video="mainVideo" id=subtitle]] +[[!template text="a primitive type like integer," start="00:03:41.280" video="mainVideo" id=subtitle]] +[[!template text="you can dispatch based on the value," start="00:03:42.879" video="mainVideo" id=subtitle]] +[[!template text="you can dispatch on multiple arguments," start="00:03:45.360" video="mainVideo" id=subtitle]] +[[!template text="and there's also a default dispatch" start="00:03:47.599" video="mainVideo" id=subtitle]] +[[!template text="that will get applied" start="00:03:49.599" video="mainVideo" id=subtitle]] +[[!template text="if there's no others that are defined." start="00:03:50.688" video="mainVideo" id=subtitle]] +[[!template text="If you don't have a default," start="00:03:53.200" video="mainVideo" id=subtitle]] +[[!template text="then you'll just get an error" start="00:03:54.319" video="mainVideo" id=subtitle]] +[[!template text="from the system," start="00:03:55.439" video="mainVideo" id=subtitle]] +[[!template text="and if that doesn't cover it," start="00:03:56.480" video="mainVideo" id=subtitle]] +[[!template text="you can even define your own." start="00:03:57.439" video="mainVideo" id=subtitle]] +[[!template text="Definition is with the" start="00:03:59.040" video="mainVideo" id=subtitle]] +[[!template text="`cl-generic-generalizers`," start="00:04:00.239" video="mainVideo" id=subtitle]] +[[!template text="which is itself a generic function." start="00:04:01.760" video="mainVideo" id=subtitle]] +[[!template text="Much of CLOS is built in CLOS," start="00:04:03.680" video="mainVideo" id=subtitle]] +[[!template text="which I think is really cool." start="00:04:05.680" video="mainVideo" id=subtitle]] +[[!template text="In addition to all that," start="00:04:08.319" video="mainVideo" id=subtitle]] +[[!template text="you have four different types of methods," start="00:04:09.599" video="mainVideo" id=subtitle]] +[[!template text="and those are distinguished by" start="00:04:12.319" video="mainVideo" id=subtitle]] +[[!template text="what's called a qualifier." start="00:04:13.680" video="mainVideo" id=subtitle]] +[[!template text="Every function can have methods" start="00:04:16.000" video="mainVideo" id=subtitle]] +[[!template text="that have all four different" start="00:04:18.400" video="mainVideo" id=subtitle]] +[[!template text="types of qualifiers," start="00:04:20.239" video="mainVideo" id=subtitle]] +[[!template text="and based on your class inheritance," start="00:04:21.280" video="mainVideo" id=subtitle]] +[[!template text="you might have multiple of each type." start="00:04:22.960" video="mainVideo" id=subtitle]] +[[!template text="There's the primary method," start="00:04:25.680" video="mainVideo" id=subtitle]] +[[!template text="which is equivalent to the method" start="00:04:26.800" video="mainVideo" id=subtitle]] +[[!template text="in any other OOP system," start="00:04:28.560" video="mainVideo" id=subtitle]] +[[!template text="so we're not going to cover that too much." start="00:04:29.919" video="mainVideo" id=subtitle]] +[[!template text="Then there's a `before` method." start="00:04:32.160" video="mainVideo" id=subtitle]] +[[!template text="This is evaluated before" start="00:04:33.759" video="mainVideo" id=subtitle]] +[[!template text="the primary method for side effects," start="00:04:35.600" video="mainVideo" id=subtitle]] +[[!template text="and its return value is discarded." start="00:04:37.440" video="mainVideo" id=subtitle]] +[[!template text="There's an `after` method," start="00:04:40.080" video="mainVideo" id=subtitle]] +[[!template text="which is the same but happens after" start="00:04:41.120" video="mainVideo" id=subtitle]] +[[!template text="the method has finished evaluating." start="00:04:42.560" video="mainVideo" id=subtitle]] +[[!template text="And then there's an `around` method" start="00:04:44.479" video="mainVideo" id=subtitle]] +[[!template text="that happens around all the other three." start="00:04:46.639" video="mainVideo" id=subtitle]] +[[!template text="And by using these types of methods" start="00:04:49.199" video="mainVideo" id=subtitle]] +[[!template text="and using class inheritance" start="00:04:51.120" video="mainVideo" id=subtitle]] +[[!template text="to compose them into your classes," start="00:04:52.560" video="mainVideo" id=subtitle]] +[[!template text="you can add some really powerful" start="00:04:54.560" video="mainVideo" id=subtitle]] +[[!template text="mixin type functionality." start="00:04:56.479" video="mainVideo" id=subtitle]] +[[!template text="You can use before and after" start="00:04:58.240" video="mainVideo" id=subtitle]] +[[!template text="to build things like logging," start="00:04:59.764" video="mainVideo" id=subtitle]] +[[!template text="and you can use around" start="00:05:01.280" video="mainVideo" id=subtitle]] +[[!template text="to implement things like memoization." start="00:05:02.479" video="mainVideo" id=subtitle]] +[[!template text="If you've done much Emacs Lisp programming," start="00:05:04.880" video="mainVideo" id=subtitle]] +[[!template text="those before after and around" start="00:05:06.720" video="mainVideo" id=subtitle]] +[[!template text="might jog your memory because" start="00:05:08.160" video="mainVideo" id=subtitle]] +[[!template text="they're the same features you get" start="00:05:09.919" video="mainVideo" id=subtitle]] +[[!template text="with Emacs's built-in function advice." start="00:05:11.440" video="mainVideo" id=subtitle]] +[[!template text="The thing with function advice is that" start="00:05:14.160" video="mainVideo" id=subtitle]] +[[!template text="it only works on functions" start="00:05:15.680" video="mainVideo" id=subtitle]] +[[!template text="in the global namespace," start="00:05:17.199" video="mainVideo" id=subtitle]] +[[!template text="and there's no kind of conditionality," start="00:05:18.240" video="mainVideo" id=subtitle]] +[[!template text="they always get dispatched" start="00:05:20.360" video="mainVideo" id=subtitle]] +[[!template text="when that function is invoked." start="00:05:21.840" video="mainVideo" id=subtitle]] +[[!template text="The nice thing about the CLOS system is that" start="00:05:23.440" video="mainVideo" id=subtitle]] +[[!template text="whether they get invoked or not" start="00:05:25.600" video="mainVideo" id=subtitle]] +[[!template text="depends on whether they exist in" start="00:05:27.039" video="mainVideo" id=subtitle]] +[[!template text="the class hierarchy," start="00:05:28.872" video="mainVideo" id=subtitle]] +[[!template text="so you can add them to your" start="00:05:30.160" video="mainVideo" id=subtitle]] +[[!template text="class hierarchy if you want" start="00:05:31.520" video="mainVideo" id=subtitle]] +[[!template text="that extra functionality" start="00:05:32.880" video="mainVideo" id=subtitle]] +[[!template text="like logging or memoization," start="00:05:34.000" video="mainVideo" id=subtitle]] +[[!template text="and you can exclude it if you don't." start="00:05:35.440" video="mainVideo" id=subtitle]] +[[!template text="I think that's really powerful" start="00:05:37.120" video="mainVideo" id=subtitle]] +[[!template text="and a very interesting way of doing it." start="00:05:38.320" video="mainVideo" id=subtitle]] +[[!template text="It also supports multiple inheritance," start="00:05:42.639" video="mainVideo" id=subtitle]] +[[!template text="which is the mechanism that you can use" start="00:05:44.639" video="mainVideo" id=subtitle]] +[[!template text="to compose all these different kinds of" start="00:05:46.639" video="mainVideo" id=subtitle]] +[[!template text="behaviors into a single object that does" start="00:05:48.560" video="mainVideo" id=subtitle]] +[[!template text="all the things that you want." start="00:05:50.479" video="mainVideo" id=subtitle]] +[[!template text="Here's a quick example of a logger." start="00:05:52.240" video="mainVideo" id=subtitle]] +[[!template text="So, you can see the class just has" start="00:05:54.720" video="mainVideo" id=subtitle]] +[[!template text="a single slot called `messages`," start="00:05:56.240" video="mainVideo" id=subtitle]] +[[!template text="it has a `log` method" start="00:05:58.319" video="mainVideo" id=subtitle]] +[[!template text="that pushes a new message," start="00:05:59.840" video="mainVideo" id=subtitle]] +[[!template text="which is a format string, into that," start="00:06:01.440" video="mainVideo" id=subtitle]] +[[!template text="and then it will return them back out," start="00:06:03.840" video="mainVideo" id=subtitle]] +[[!template text="or it'll just return the latest." start="00:06:05.520" video="mainVideo" id=subtitle]] +[[!template text="And there's a simple example" start="00:06:07.280" video="mainVideo" id=subtitle]] +[[!template text="that shows it logging," start="00:06:08.479" video="mainVideo" id=subtitle]] +[[!template text="and then shows it coming back out," start="00:06:09.600" video="mainVideo" id=subtitle]] +[[!template text="pretty much what you would expect." start="00:06:11.280" video="mainVideo" id=subtitle]] +[[!template text="Here's another class that adapts" start="00:06:14.080" video="mainVideo" id=subtitle]] +[[!template text="the `emms-player` to the `logger` class." start="00:06:16.400" video="mainVideo" id=subtitle]] +[[!template text="It only extends the logger" start="00:06:19.039" video="mainVideo" id=subtitle]] +[[!template text="because it doesn't need any features" start="00:06:20.560" video="mainVideo" id=subtitle]] +[[!template text="of the `emms-player` class itself." start="00:06:22.400" video="mainVideo" id=subtitle]] +[[!template text="It just implements methods that dispatch" start="00:06:25.039" video="mainVideo" id=subtitle]] +[[!template text="based on it being that logging player class," start="00:06:27.440" video="mainVideo" id=subtitle]] +[[!template text="and you can see it logs whenever" start="00:06:30.240" video="mainVideo" id=subtitle]] +[[!template text="a track is started or stopped," start="00:06:31.759" video="mainVideo" id=subtitle]] +[[!template text="and it also adds some track" start="00:06:34.240" video="mainVideo" id=subtitle]] +[[!template text="to tell you whether or not" start="00:06:36.240" video="mainVideo" id=subtitle]] +[[!template text="the track was playable," start="00:06:37.520" video="mainVideo" id=subtitle]] +[[!template text="that is using the around method." start="00:06:38.560" video="mainVideo" id=subtitle]] +[[!template text="So, you can see we have all three methods" start="00:06:41.199" video="mainVideo" id=subtitle]] +[[!template text="before, after, and around in this class," start="00:06:43.199" video="mainVideo" id=subtitle]] +[[!template text="so you can see how those work." start="00:06:45.280" video="mainVideo" id=subtitle]] +[[!template text="Then you need one more," start="00:06:48.160" video="mainVideo" id=subtitle]] +[[!template text="which is the class" start="00:06:49.440" video="mainVideo" id=subtitle]] +[[!template text="that mixes it all together," start="00:06:50.184" video="mainVideo" id=subtitle]] +[[!template text="So, that's the `logging-player-mpv`," start="00:06:51.759" video="mainVideo" id=subtitle]] +[[!template text="and it extends both the `logging-player` class" start="00:06:54.080" video="mainVideo" id=subtitle]] +[[!template text="and the `emms-player-mpv` class." start="00:06:56.639" video="mainVideo" id=subtitle]] +[[!template text="What's really interesting about this is" start="00:06:59.680" video="mainVideo" id=subtitle]] +[[!template text="that even though the logging player is" start="00:07:01.440" video="mainVideo" id=subtitle]] +[[!template text="part of the `emms-player` hierarchy," start="00:07:03.360" video="mainVideo" id=subtitle]] +[[!template text="it doesn't depend on" start="00:07:05.520" video="mainVideo" id=subtitle]] +[[!template text="a specific implementation," start="00:07:06.472" video="mainVideo" id=subtitle]] +[[!template text="so you can combine the two different" start="00:07:08.240" video="mainVideo" id=subtitle]] +[[!template text="classes that lets the logging class" start="00:07:10.400" video="mainVideo" id=subtitle]] +[[!template text="only care about logging," start="00:07:12.639" video="mainVideo" id=subtitle]] +[[!template text="and the `emms-player` class" start="00:07:13.919" video="mainVideo" id=subtitle]] +[[!template text="only care about playing," start="00:07:15.440" video="mainVideo" id=subtitle]] +[[!template text="and that is a really nice" start="00:07:17.039" video="mainVideo" id=subtitle]] +[[!template text="way of separating your concerns" start="00:07:18.240" video="mainVideo" id=subtitle]] +[[!template text="that I think is very powerful." start="00:07:19.599" video="mainVideo" id=subtitle]] +[[!template text="Here's a quick example of" start="00:07:21.440" video="mainVideo" id=subtitle]] +[[!template text="just how that works," start="00:07:22.515" video="mainVideo" id=subtitle]] +[[!template text="and you can see the `unplayable`" start="00:07:23.599" video="mainVideo" id=subtitle]] +[[!template text="track is not playable," start="00:07:25.199" video="mainVideo" id=subtitle]] +[[!template text="and it gets logged as such," start="00:07:26.160" video="mainVideo" id=subtitle]] +[[!template text="`foo` is playable, and you can see" start="00:07:27.840" video="mainVideo" id=subtitle]] +[[!template text="the logs in started and stopped." start="00:07:29.360" video="mainVideo" id=subtitle]] +[[!template text="So, you can see it's having" start="00:07:31.120" video="mainVideo" id=subtitle]] +[[!template text="the side effects from those methods," start="00:07:32.560" video="mainVideo" id=subtitle]] +[[!template text="and it's also returning" start="00:07:34.000" video="mainVideo" id=subtitle]] +[[!template text="the value off the player as well." start="00:07:36.960" video="mainVideo" id=subtitle]] +[[!template text="I think this system has a bunch of" start="00:07:40.319" video="mainVideo" id=subtitle]] +[[!template text="really nice properties." start="00:07:41.599" video="mainVideo" id=subtitle]] +[[!template text="First and foremost," start="00:07:43.120" video="mainVideo" id=subtitle]] +[[!template text="it feels like a normal Lisp," start="00:07:44.080" video="mainVideo" id=subtitle]] +[[!template text="all you're doing is calling functions," start="00:07:45.840" video="mainVideo" id=subtitle]] +[[!template text="there's no magic involved." start="00:07:47.360" video="mainVideo" id=subtitle]] +[[!template text="Also, you can use either or both of the" start="00:07:49.840" video="mainVideo" id=subtitle]] +[[!template text="classes or generic functions." start="00:07:51.919" video="mainVideo" id=subtitle]] +[[!template text="If you only need to" start="00:07:53.840" video="mainVideo" id=subtitle]] +[[!template text="encapsulate data into a structure," start="00:07:55.120" video="mainVideo" id=subtitle]] +[[!template text="then you can only use classes," start="00:07:56.960" video="mainVideo" id=subtitle]] +[[!template text="you don't have to use generic functions." start="00:07:58.479" video="mainVideo" id=subtitle]] +[[!template text="And if you only need dynamic dispatch," start="00:08:00.400" video="mainVideo" id=subtitle]] +[[!template text="you can only implement" start="00:08:02.080" video="mainVideo" id=subtitle]] +[[!template text="a generic function and methods." start="00:08:03.068" video="mainVideo" id=subtitle]] +[[!template text="You don't get forced into a model" start="00:08:04.720" video="mainVideo" id=subtitle]] +[[!template text="where you have to use both." start="00:08:06.560" video="mainVideo" id=subtitle]] +[[!template text="You can mix and match for" start="00:08:08.000" video="mainVideo" id=subtitle]] +[[!template text="whatever needs your program has," start="00:08:09.247" video="mainVideo" id=subtitle]] +[[!template text="which I think is really amazing." start="00:08:10.800" video="mainVideo" id=subtitle]] +[[!template text="Any value can conform to an interface," start="00:08:13.039" video="mainVideo" id=subtitle]] +[[!template text="meaning a generic function." start="00:08:15.440" video="mainVideo" id=subtitle]] +[[!template text="So, you don't have to use those classes." start="00:08:17.039" video="mainVideo" id=subtitle]] +[[!template text="You can even implement" start="00:08:19.520" video="mainVideo" id=subtitle]] +[[!template text="a generic function over `nil`," start="00:08:20.479" video="mainVideo" id=subtitle]] +[[!template text="which gives you those really nice" start="00:08:22.240" video="mainVideo" id=subtitle]] +[[!template text="properties of Lisp," start="00:08:23.599" video="mainVideo" id=subtitle]] +[[!template text="where you have nil-punning, you know," start="00:08:24.800" video="mainVideo" id=subtitle]] +[[!template text="if you take the head of a nil list," start="00:08:26.460" video="mainVideo" id=subtitle]] +[[!template text="then the output is `nil`," start="00:08:28.800" video="mainVideo" id=subtitle]] +[[!template text="but you can do that" start="00:08:30.479" video="mainVideo" id=subtitle]] +[[!template text="with your object system too." start="00:08:31.283" video="mainVideo" id=subtitle]] +[[!template text="And a really nice feature of that is" start="00:08:32.880" video="mainVideo" id=subtitle]] +[[!template text="that you have no possibility of" start="00:08:34.320" video="mainVideo" id=subtitle]] +[[!template text="null pointer exceptions" start="00:08:35.919" video="mainVideo" id=subtitle]] +[[!template text="like you do in other languages." start="00:08:36.959" video="mainVideo" id=subtitle]] +[[!template text="They have a calling convention" start="00:08:38.719" video="mainVideo" id=subtitle]] +[[!template text="where you call object dot method," start="00:08:39.919" video="mainVideo" id=subtitle]] +[[!template text="but in CLOS, you call a generic function," start="00:08:42.880" video="mainVideo" id=subtitle]] +[[!template text="and you just give it some arguments." start="00:08:45.600" video="mainVideo" id=subtitle]] +[[!template text="Typically, the first one is going to be" start="00:08:47.279" video="mainVideo" id=subtitle]] +[[!template text="an EIEIO class object," start="00:08:48.959" video="mainVideo" id=subtitle]] +[[!template text="but it doesn't have to be," start="00:08:51.680" video="mainVideo" id=subtitle]] +[[!template text="but because you're not calling that" start="00:08:53.200" video="mainVideo" id=subtitle]] +[[!template text="instance of an object," start="00:08:54.640" video="mainVideo" id=subtitle]] +[[!template text="there's nothing to be nil in the first place," start="00:08:55.519" video="mainVideo" id=subtitle]] +[[!template text="so there's no possibility of" start="00:08:57.279" video="mainVideo" id=subtitle]] +[[!template text="a nil pointer exception." start="00:08:58.320" video="mainVideo" id=subtitle]] +[[!template text="And then the ability to" start="00:09:00.080" video="mainVideo" id=subtitle]] +[[!template text="have multiple inheritance" start="00:09:01.376" video="mainVideo" id=subtitle]] +[[!template text="and mix in all of these different" start="00:09:02.480" video="mainVideo" id=subtitle]] +[[!template text="functionalities into your final object" start="00:09:04.000" video="mainVideo" id=subtitle]] +[[!template text="is very powerful." start="00:09:05.760" video="mainVideo" id=subtitle]] +[[!template text="Because you have multiple inheritance," start="00:09:07.279" video="mainVideo" id=subtitle]] +[[!template text="your final object that" start="00:09:09.839" video="mainVideo" id=subtitle]] +[[!template text="composes all of those things" start="00:09:11.120" video="mainVideo" id=subtitle]] +[[!template text="is both a player and a logger," start="00:09:12.560" video="mainVideo" id=subtitle]] +[[!template text="and it can be substituted into code" start="00:09:14.080" video="mainVideo" id=subtitle]] +[[!template text="that expects either of them." start="00:09:15.600" video="mainVideo" id=subtitle]] +[[!template text="It's not an adapter class" start="00:09:17.279" video="mainVideo" id=subtitle]] +[[!template text="that only allows you to do one thing," start="00:09:19.040" video="mainVideo" id=subtitle]] +[[!template text="it does both of them." start="00:09:21.360" video="mainVideo" id=subtitle]] +[[!template text="I think that's amazing." start="00:09:22.560" video="mainVideo" id=subtitle]] +[[!template text="So, here are some practical examples" start="00:09:24.800" video="mainVideo" id=subtitle]] +[[!template text="where I think maybe this" start="00:09:26.320" video="mainVideo" id=subtitle]] +[[!template text="could be a good idea." start="00:09:27.387" video="mainVideo" id=subtitle]] +[[!template text="And I like to think about," start="00:09:28.720" video="mainVideo" id=subtitle]] +[[!template text=""What is OOP actually good for?"." start="00:09:30.399" video="mainVideo" id=subtitle]] +[[!template text="I think it has three really amazing powers," start="00:09:32.320" video="mainVideo" id=subtitle]] +[[!template text="encapsulation, abstraction," start="00:09:34.640" video="mainVideo" id=subtitle]] +[[!template text="and extensibility," start="00:09:36.399" video="mainVideo" id=subtitle]] +[[!template text="so let's look at those." start="00:09:37.279" video="mainVideo" id=subtitle]] +[[!template text="Encapsulation is just keeping" start="00:09:39.200" video="mainVideo" id=subtitle]] +[[!template text="related data together." start="00:09:40.959" video="mainVideo" id=subtitle]] +[[!template text="Here's an example from the" start="00:09:42.480" video="mainVideo" id=subtitle]] +[[!template text="transmission Torrent client." start="00:09:43.680" video="mainVideo" id=subtitle]] +[[!template text="In order for it to work," start="00:09:45.360" video="mainVideo" id=subtitle]] +[[!template text="it needs to have all four of" start="00:09:46.399" video="mainVideo" id=subtitle]] +[[!template text="these variables set consistently," start="00:09:47.600" video="mainVideo" id=subtitle]] +[[!template text="but if you use the customization interface," start="00:09:49.920" video="mainVideo" id=subtitle]] +[[!template text="they're kind of strewn all over the buffer" start="00:09:52.240" video="mainVideo" id=subtitle]] +[[!template text="because that shows them alphabetically" start="00:09:53.920" video="mainVideo" id=subtitle]] +[[!template text="by variable name instead of" start="00:09:55.760" video="mainVideo" id=subtitle]] +[[!template text="grouping them logically by function." start="00:09:57.040" video="mainVideo" id=subtitle]] +[[!template text="You also have all these" start="00:09:59.920" video="mainVideo" id=subtitle]] +[[!template text="in the global namespace," start="00:10:01.327" video="mainVideo" id=subtitle]] +[[!template text="so you need this disambiguation in front," start="00:10:02.480" video="mainVideo" id=subtitle]] +[[!template text="you have to have a transmission prefix," start="00:10:04.720" video="mainVideo" id=subtitle]] +[[!template text="so it's kind of ugly." start="00:10:06.800" video="mainVideo" id=subtitle]] +[[!template text="An alternative example would be to" start="00:10:08.720" video="mainVideo" id=subtitle]] +[[!template text="encapsulate all of that" start="00:10:10.240" video="mainVideo" id=subtitle]] +[[!template text="in a single class." start="00:10:11.760" video="mainVideo" id=subtitle]] +[[!template text="This has one slot for each of those values," start="00:10:13.360" video="mainVideo" id=subtitle]] +[[!template text="except the username" start="00:10:16.160" video="mainVideo" id=subtitle]] +[[!template text="and password is broken out," start="00:10:17.040" video="mainVideo" id=subtitle]] +[[!template text="there was only one in the previous example," start="00:10:18.000" video="mainVideo" id=subtitle]] +[[!template text="but it works pretty much the same." start="00:10:20.240" video="mainVideo" id=subtitle]] +[[!template text="The really neat thing about this is that" start="00:10:23.120" video="mainVideo" id=subtitle]] +[[!template text="the customization interface understands" start="00:10:25.200" video="mainVideo" id=subtitle]] +[[!template text="how to customize EIEIO objects," start="00:10:27.279" video="mainVideo" id=subtitle]] +[[!template text="so you can set your custom variable" start="00:10:29.920" video="mainVideo" id=subtitle]] +[[!template text="to the value of an object," start="00:10:32.640" video="mainVideo" id=subtitle]] +[[!template text="and in the customization interface," start="00:10:34.000" video="mainVideo" id=subtitle]] +[[!template text="it shows you all of the fields," start="00:10:35.760" video="mainVideo" id=subtitle]] +[[!template text="and it lets you edit the values" start="00:10:37.040" video="mainVideo" id=subtitle]] +[[!template text="of those slots directly." start="00:10:38.399" video="mainVideo" id=subtitle]] +[[!template text="So, that keeps that logical grouping" start="00:10:40.079" video="mainVideo" id=subtitle]] +[[!template text="that I think makes things really easy to use." start="00:10:41.760" video="mainVideo" id=subtitle]] +[[!template text="Another thing it's really good at is" start="00:10:44.800" video="mainVideo" id=subtitle]] +[[!template text="abstraction, and this is really core to" start="00:10:46.160" video="mainVideo" id=subtitle]] +[[!template text="a lot of what Emacs does" start="00:10:48.268" video="mainVideo" id=subtitle]] +[[!template text="because it runs on so many different systems," start="00:10:49.408" video="mainVideo" id=subtitle]] +[[!template text="and it works with so many different" start="00:10:51.200" video="mainVideo" id=subtitle]] +[[!template text="kinds of similar tools." start="00:10:53.308" video="mainVideo" id=subtitle]] +[[!template text="Here's an example from" start="00:10:55.120" video="mainVideo" id=subtitle]] +[[!template text="the built-in SQL implementation." start="00:10:56.109" video="mainVideo" id=subtitle]] +[[!template text="This is the definition of" start="00:10:58.079" video="mainVideo" id=subtitle]] +[[!template text="the postgres backend," start="00:10:59.360" video="mainVideo" id=subtitle]] +[[!template text="there's one of these for" start="00:11:01.040" video="mainVideo" id=subtitle]] +[[!template text="every supported database backend." start="00:11:02.160" video="mainVideo" id=subtitle]] +[[!template text="And you can see, this is a pretty" start="00:11:04.000" video="mainVideo" id=subtitle]] +[[!template text="classic interface abstraction pattern." start="00:11:05.440" video="mainVideo" id=subtitle]] +[[!template text="On the left-hand side," start="00:11:08.480" video="mainVideo" id=subtitle]] +[[!template text="you have a symbol that's common" start="00:11:09.680" video="mainVideo" id=subtitle]] +[[!template text="among all the database backends," start="00:11:10.880" video="mainVideo" id=subtitle]] +[[!template text="and the code that doesn't" start="00:11:12.399" video="mainVideo" id=subtitle]] +[[!template text="know about the implementation can use," start="00:11:14.160" video="mainVideo" id=subtitle]] +[[!template text="no matter what implementation" start="00:11:16.240" video="mainVideo" id=subtitle]] +[[!template text="is being specified." start="00:11:17.519" video="mainVideo" id=subtitle]] +[[!template text="On the right-hand side," start="00:11:19.040" video="mainVideo" id=subtitle]] +[[!template text="you have the implementation" start="00:11:20.000" video="mainVideo" id=subtitle]] +[[!template text="specific values," start="00:11:21.120" video="mainVideo" id=subtitle]] +[[!template text="in some cases these are just strings," start="00:11:22.560" video="mainVideo" id=subtitle]] +[[!template text="or regexes, and in others" start="00:11:24.399" video="mainVideo" id=subtitle]] +[[!template text="those are actual functions." start="00:11:25.760" video="mainVideo" id=subtitle]] +[[!template text="So, really this already is" start="00:11:27.519" video="mainVideo" id=subtitle]] +[[!template text="object orientation," start="00:11:29.440" video="mainVideo" id=subtitle]] +[[!template text="it's just an ad-hoc system for it," start="00:11:30.720" video="mainVideo" id=subtitle]] +[[!template text="but you don't have to use an ad-hoc system" start="00:11:32.959" video="mainVideo" id=subtitle]] +[[!template text="because there's this" start="00:11:34.880" video="mainVideo" id=subtitle]] +[[!template text="nice formal one instead." start="00:11:35.519" video="mainVideo" id=subtitle]] +[[!template text="Another thing that it's" start="00:11:38.000" video="mainVideo" id=subtitle]] +[[!template text="really good at is extensibility," start="00:11:38.880" video="mainVideo" id=subtitle]] +[[!template text="we saw some of that with" start="00:11:40.959" video="mainVideo" id=subtitle]] +[[!template text="the emms-player example earlier." start="00:11:42.160" video="mainVideo" id=subtitle]] +[[!template text="But here's another thing I think" start="00:11:44.800" video="mainVideo" id=subtitle]] +[[!template text="it would be interesting to explore." start="00:11:46.160" video="mainVideo" id=subtitle]] +[[!template text="Emacs has this idea of derived modes" start="00:11:48.720" video="mainVideo" id=subtitle]] +[[!template text="where you have a mode that's based on" start="00:11:51.279" video="mainVideo" id=subtitle]] +[[!template text="another, and that's a pretty clear" start="00:11:52.639" video="mainVideo" id=subtitle]] +[[!template text="inheritance pattern straight out of OOP" start="00:11:54.639" video="mainVideo" id=subtitle]] +[[!template text="as far as I'm concerned." start="00:11:57.040" video="mainVideo" id=subtitle]] +[[!template text="What would it look like" start="00:11:58.560" video="mainVideo" id=subtitle]] +[[!template text="if major modes were EIEIO classes," start="00:12:00.079" video="mainVideo" id=subtitle]] +[[!template text="and you could extend your mode" start="00:12:02.959" video="mainVideo" id=subtitle]] +[[!template text="by extending the class." start="00:12:04.800" video="mainVideo" id=subtitle]] +[[!template text="I think that's a really interesting idea," start="00:12:06.399" video="mainVideo" id=subtitle]] +[[!template text="and I'd like to explore that more." start="00:12:08.240" video="mainVideo" id=subtitle]] +[[!template text="In conclusion, I think EIEIO is amazing," start="00:12:10.880" video="mainVideo" id=subtitle]] +[[!template text="and I had no idea that such a powerful" start="00:12:14.079" video="mainVideo" id=subtitle]] +[[!template text="object orientation system" start="00:12:16.079" video="mainVideo" id=subtitle]] +[[!template text="was available in the Emacs." start="00:12:18.079" video="mainVideo" id=subtitle]] +[[!template text="My goal with this talk" start="00:12:20.160" video="mainVideo" id=subtitle]] +[[!template text="is for anyone who writes Emacs Lisp," start="00:12:21.519" video="mainVideo" id=subtitle]] +[[!template text="to look at these classes of problems," start="00:12:23.519" video="mainVideo" id=subtitle]] +[[!template text="encapsulation, abstraction," start="00:12:25.360" video="mainVideo" id=subtitle]] +[[!template text="and extensibility," start="00:12:27.360" video="mainVideo" id=subtitle]] +[[!template text="and if you run into" start="00:12:28.639" video="mainVideo" id=subtitle]] +[[!template text="those problems in your code," start="00:12:29.600" video="mainVideo" id=subtitle]] +[[!template text="instead of immediately reaching" start="00:12:31.279" video="mainVideo" id=subtitle]] +[[!template text="and building your own system," start="00:12:33.279" video="mainVideo" id=subtitle]] +[[!template text="I want you to think:" start="00:12:34.959" video="mainVideo" id=subtitle]] +[[!template text=""Oh there's a thing for that," start="00:12:35.760" video="mainVideo" id=subtitle]] +[[!template text="and I can just use it."" start="00:12:37.279" video="mainVideo" id=subtitle]] +[[!template text="That's my talk, thanks." start="00:12:39.040" video="mainVideo" id=subtitle]] +[[!template text="Hack on!" start="00:12:40.560" video="mainVideo" id=subtitle]] +[[!template text="captions by bhavin192 (Bhavin Gandhi)" start="00:12:41.560" video="mainVideo" id=subtitle]] |