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