Some problems of modernizing Emacs
Eduardo Ochs (he/him) - Pronunciation: Oks, IRC: edrx, http://anggtwu.net/, more info at http://anggtwu.net/contact.html., eduardoochs@gmail.com
Format: 26-min talk ; Q&A: IRC Etherpad: https://pad.emacsconf.org/2025-modern
Etherpad: https://pad.emacsconf.org/2025-modern
Status: Q&A to be extracted from the room recordings
Duration: 25:22 minutes00:00.000 Introduction 01:05.000 The main themes of this video 02:18.000 Inner views of Emacs objects 02:54.000 Older Emacses 03:35.000 Newer Emacses 05:30.000 Help buttons 06:41.000 Anyone can learn Lisp in one day 09:34.000 Lambdas for beginners broken 12:59.302 Demo 17:29.120 Printing something in different ways for lambdas 21:52.840 Exploring buttons 22:42.160 Some design decisions behind eev 24:05.800 Tests
Description
https://anggtwu.net/emacsconf2025.html
This talk is going to be a reworked version of the incomplete video in http://anggtwu.net/2025-modern.html. I will start by presenting several notions of "simplicity" and "elegance", and show that when I started learning Elisp it was "simple" and "elegant" in a way that it no longer is; then I will show how to fix some tiny parts of the problem by 1) using functions based on `cl-prin1', 2) redefining some printing methods with "(cl-defmethod cl-print-object …)", and 3) using Common Lisp to understand some recent parts of Elisp that are not well-documented.
About the speaker:
Eduardo is the author of an Emacs package called eev that makes total sense to a handful of people and no sense at all to practically everyone else - except for one part of eev, called "eepitch". He intends to explain the reasons for that in his talk.
Discussion / notes
- Q: [from IRC] why the lambda representation has recently changed
to vector-like?
- A: It is easier to debug Emacs if different kinds of objects have different types... keeping everything as lists is better for quick-and-dirty code, but the developers wanted something that felt less "dirty"...
- Q: Do you have hints for integrating eev into an already existing
workflow?
- A: I need to understand the other workflows to see what I can recommend... can we discuss that on chat? If your workflow includes Org code blocks then I will learn a lot from your workflow too...
- I was hoping for some document with some general notes or ideas. Right now eev feels very 'dominant'. While it works great I find it difficult to mix eev and other Emacs tools
- Which other tools? Can we discuss examples? I was able to integrate eev with practically all the other packages the I know...
- Q: [from IRC] What do you think of org-mode and its executable src
blocks? That seems to overlap with what eev seemed to provide.
- A: I need to learn more about Org and source blocks!!! The problem is that every time that I tried to learn source blocks I started to ask many technical questions about the details and got lost in a big maze of rabbit holes... see: <https://anggtwu.net/2021-org-for-non-users.html> - I even tried to write functions that would display the data structures behind source blocks, but at some point I gave up and decided that I would only come back when I had people who could help me... =(
- A: in short: when I tried to use Org mode I was always asking the wrong questions and trying to understand internal details that the developers treated as very advanced
- Q: I just tested on SBCL, Guile and Chez Scheme, and all of them use
opaque objects for functions (Chez:
#<procedure square>, SBCL:#<FUNCTION F>). Why is Emacs Lisp changing to using semi-opaque vectors considered so bad? (Or is just making them fully opaque better for beginners?)- Note: on SBCL you can inspect that function object and see both the lisp code and the machine code it compiles to
- A: It is not bad at all!
Q: What defines `find-classtree'?
I must confess I am still confused about eev. same with hyperbole.
- A: eev doesn't make any sense from the description and the sales blurbs, all the few people who learned it learned it from the tutorials. but that video has a big example that is very easy to run it the person has eev installed - it starts a bit after 13:00.
- I often find myself wishing other systems had a help system like Emacs.
- It took me about 5 years to move from Space & Doom to vanilla Emacs 🤣
- Now that I think about it, it was about the same for me.
- it was less about learning elisp and more about finding the motivation & internal justification to start from scratch. David Wilson's tutorials helped propel me as well
- did you switch from vim/evil bindings to "Emacs Standard" bindings?
- The Doom & Spacemacs Frameworks obfuscate how vanilla Emacs actually works... and so after a while it became a barrier
- not really, I use evil when writing code but tend to stick to vanilla bindings for most other buffers
- My own motivation was that one day Spacemacs broke an important org-mode keybinding (M-RET) in a way that I couldn't work around. I had managed to learn a decent amount of Elisp by then, so I decided to go try my first vanilla config.
- I think it took me a few months
- me similar: I use evil mode for all prose and programming buffers but Emacs modes for everything else.
- I had installed too many packages that I didn't understand at all
- I was really unhappy with performance as I started to rely more on LSP modes (this was before the bytecode implementation). Switching to vanilla & moving to Eglot really helped with that, then of course the bytecode changes make it a non-issue now
- thanks! just started using emacs about 4-5 months ago via Doom. But I can't help think I've skipped some important learnings.
- I was quite happy when I got my first taste of native compilation. It improved Elisp performance tremendously.
- I really recommend giving vanilla a try! You can use this trick to setup a parallel config so you can try it out before scrapping your current setup: https://stackoverflow.com/a/58039656/315827
- That SO strikes me as slightly more complicated that necessary.. I would usually do it inline, like: emacs -Q -eval '(setq user-emacs-directory "~/emacs.1.d")' [filename, maybe]
- There is also the --init-dir flag.
- Fair comment, with your version it could be nice to build a shell function or alias so you can have multiple configs at one time
- shell function or alias is a great idea! taking a note to set that up for myself!
- Q: following along a little using IELM... which version of Emacs was used in the recording? My (symbol-function 'foo) is giving #f(lambda (a b) [t] (+ a b))
- A: 31
- I get #[(a b) ((+ a b)) (t)] (not nil for the last vector element as shown in the presentation)
- Emacs 31 would be a development build (vs from the release branch) so it's possible two different builds of 31 could have subtle differences depending on which commit was the last included in the given builds.
- A: the demo is here
- https://anggtwu.net/2025-modern/00-try-this.html
- https://anggtwu.net/2025-modern/00-try-this
- I think that people can run the demo with just this (find-wget "https://anggtwu.net/2025-modern/00-try-this") except for one line that with give an error because it depends on a function that is not in ELPA - actually not even on the github version yet...
- if anyone has eev installed and wants to try it please tell me... I think that one line of the demo calls a function that is not in the version of eev that is ELPA yet
- Q: What do the leading red * in the left window mean?
- A: https://anggtwu.net/eepitch.html#test-blocks
- I was using eev for a month or so then my guix package broke and I am too lazy to fix it
- Very informative talk.
- Thank you edrx! eev has been on my list of things to check for some time!
- Super cool seeing pieces of the workflow with eev, gives me some ideas!
Transcript (unedited)
cl-print
family of functions, for example,
cl-prin1-to-string, and here are some
examples of the kind of output that we
are going to see...
for example, if we run these two lines
here the first line defines a function foo
and the second line sets o to the
internal view of the definition of foo.
o would be just a
list that looks... that would look very
similar to this line here... but in newer
Emacses the result of this - I mean, the
the contents of o is this thing here,
that looks quite different
from this definition.
So, in older Emacses
the contents of the
function cell of o...
sorry, of the function cell of foo,
would be an "old-style lambda",
that would be just a list like this...
prin1...
and the second semicanonical printed
representation is like this -
it looks like a list...
it looks somewhat like this definition
of foo here, but it has this
:dynbind symbol here...
and it turns out that when we use
the cl-print family of functions we can
reconfigure how things are printed...
and I'm going to show several interesting
ways of reconfiguring how lambdas are printed,
and one of the ways is going to
be like this.
We can also use the cl-print
functions with my indentation tricks to
to display how types, or classes, are
viewed internally by Emacs, and this is a
big example...
This is what Emacs considers as being
the definition of the type
cl-structure-class,
class and it is this big thing here.
I edited it very lightly...
I just deleted some line breaks here.
describe-type
or my variant of describe-type,
and we get a help buffer
that looks like this, in which
these blue things that are underlined
are "buttons", in the classical sense...
you can click on these buttons, or type
RET on these buttons, and you will be
taken to another help page, that is
generated dynamically...
and you can navigate back and forth...
and well, whatever...
and I'm going to explain my
problems with these kinds of help buffers
and what I'm trying to do to
overcome these problems...
foo, and
if we run this defun here it stores a
certain anonymous function in the
"function cell" of the symbol foo...
and in Emacs, until some time ago
if we did that and and if we ran
this expression here the result
would be 42,
because of this line here, and if we
ran this line here the result would be
the anonymous function corresponding to
this defun here...
but now this has changed...
the result of this thing here is this
vector-like lambda here - but that doesn't
matter much now...
So, until some time ago
if we did that and if we ran
this expression here, (foo foo)...
Emacs would do this: it would
replace the first foo by this
anonymous function here, it would replace
the second foo by the value of foo as a
variable, that is 42,
and it would evaluate this, and the
result would be 420.
So, again, we used to have this slogan
here, "anyone can learn Lisp in one day"...
but now this is gone.
Let me show... let me talk
a bit more about why...
foo...
and they would see something elegant and
mind-blowing... and they would start to love
Lisp immediately.
Now what they get - what they see -
is a tiny part of a very complex structure
that is very powerful but that is
very difficult to understand...
and now our beginners are overwhelmed
instead of mind-blown. Note that I said "black box" here.
Let me explain the term.
We can open what's inside of foo...
we can open foo to see the contents of
the symbol foo, and we can try to see
what's in the function cell of the
symbol foo...
so we can open the box, but what we get
is something very difficult to understand,
and so I'm going to say that
when this happens that box is black.
It is not totally black - we can open open it -
but we don't understand what is going on there,
so we declare that that is black.
And... when these things started to happen
I was overwhelmed -
and in this video I'm going to pretend
that I was not the only person
that was overwhelmed
by these new structures
that are not so elegant
as the ones that we had before.
Anyway...
f8s in the right places.
Remember that when we type f8
on a line that starts with two red stars,
eev treats that line as a comment.
So I'm going to start here... Note that it says in the bottom
of the screen that this is a comment.
We are going to run this to download some files...
Now the files are there...
This find-2a here shows a certain file
at the window at the right,
but we don't need to pay attention to that.
And this thing loads that file.
So when we load that file, it defines some functions here
that are going to be used by the rest of the examples.
Now we can run this thing here... Note that
we just defined some functions
and then we ran these functions here... find-eoutput-2a...
and they show some things in the window at the right.
These things are boring.
When we run adt-insert with argument 42,
it just shows a 42, in this way...
The other ones show other numbers... and so on.
And... what happens when we modify
this function here, adt-2,
by adding and removing advices to it?
The idea is that people can run
this thing here several times,
watching the window at the right,
because the results are going to be shown there.
So, in the first moment, when we run...
no, no, sorry, sorry, let me run it again.
In the first moment when we run adt-2
it just shows a 2, and then we modify it in a certain way,
and we run it again,
and now before showing the 2 it shows a 1, mysteriously,
and then we add something to be run after the 2,
And we run it again,
and now adt-2 shows these three things.
And then we remove the advices,
we remove these other things,
and when we run adt-2 again, it shows only ;; --> 2.
It's impossible to understand that in the first time,
so we can run that several times... to see how things work.
And now we want to understand
what changes in the function adt-2...
how it is modified internally.
I'm calling that the internal view of the function,
and we are going to compare
several internal views of the function adt-2.
I'm going to reset the function adt-2
by removing the advices and placing the advices on it again...
and if we just pretty-print this function here,
the symbol... the value of this symbol here as a function,
it is something very ugly.
But if we print it in another way, with cl-prin1,
then we get something that is much nicer...
but that is not indented. And if we use this thing here,
cl-prin2 instead of cl-prin1, it becomes indented.
So let's try it again.
Here is the current view of what is adt-2.
So, the original adt-insert is here...
and here are some modifications
that were added by the advices.
And we can run these things many times
to understand what each step does.
But my suggestion is: in the first time
just run everything very quickly...
and then you run it again,
paying attention to the parts that look more interesting.
adt-2 in several different ways,
and now I'm going to show how we can do the same idea
of printing something in different ways for lambdas...
that is something that I explained
in the first part of the video.
In this part of the demo we define a function foo...
this setq here defines o as
the contents of the function cell of foo...
And now we are going to print
that o in several different ways.
The default way is this one, it's very ugly,
but we can redefine how these things are printed
by just running these lines...
and if we pay attention at what's happening
at the window at the right,
we can see that we have several different
printed representations for the same thing...
and then at the last step,
we reset the printer to the default representation.
And the details are here.
If we run these lines here,
they show the definitions at the window at the right.
And this... now comes the difficult part,
in which we have to do something
besides just running things with F8. We need
a help buffer with buttons...
buttons in the traditional sense,
and we need to choose a certain button there,
or any button there,
and run M-x ee-set-button on that button.
So, let me define a struct here,
and this is some help on what is that structure.
I'm going to choose this button here
and I'm going to type M-x ee-set-button.
The message is a bit obscure.
And now we have something that displays
a lot of information about that button...
And we can also run that with just F8s.
By the way, if we want to understand
the code that's behind these things,
we can run this sexp here.
It is going to show the code here at the right.
But anyway, these first lines here...
they display the output in the echo area... Let's try...
And each one of them extracts a different part
of the information on that button.
And these other lines here create a three-window setting
in which the help buffer is shown here,
and the result of some other thing
is shown in the third window. Let's try...
So now that we have... well... I said
that we needed to choose a certain button
and run M-x ee-set-button there. We have done that...
so now this variable ee-button
contains information about the button...
And now we can run this part here
as many times as we want to...
try to understand what are the values of these things here...
and how some things start with a value that is very complex
and very difficult to understand,
and then we extract the more interesting parts.
And the details, as I said, are here.
That was the end of the demo, and my question is,
what was your reaction to that?
If your reaction was more like "wow" than like "blergh"
then you might like the last part of the video that I recorded in March,
that was very technical...
When I recorded it, I thought, oh my god, this video is very bad...
only the hardcore eev users are going to like that,
and there are less than five hardcore
eev users in the world...
f8 and M-e...
and... most people in the #emacs channel and in other places
recommend executing sexps by typing M-:, like this...
But I hate that... I think that M-: and IELM are
for people who type well, so not me...
And also, 99% of what I do is scratch code.
Very few things that I do go
into "production" - between quotes.
Questions or comments? Please e-mail eduardoochs@gmail.com
