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)]