Emacs is not just an editor (2015)
karl-voit.at
karl-voit.at
If anything, the opposite is true: those who try to diminish Emacs point out the absurdity of referring to it as an editor. To them, what has been accomplished through elisp is more of an indicator of a lack of focus or of bloat than it is of Emacs versatility.
no, that's not true.
emacs was written in the macro language of another editor, teco; teco had the macros. So, emacs was written as a new editor written on top of the old editor teco, and at that time, emacs was a set of "teco edit macros". As a user, where you used to run teco, you could instead elect to run the "edit macros"
because the authors of emacs were teco users, and macros were so useful to the teco user, yes, a macro facility was also added to emacs for the emacs users, but emacs itself was not intially those macros, it was teco macros.
I used to think that this is the least awkward combination of symbols meaning Escape, Meta, Alt, Ctrl, Shift.
It was a lot to take in at first, so I went back to neovim. But I started using org mode more and more until I finally just went all in on Emacs. Now I understand that the editor war is pointless. Bringing vim + emacs together is bliss.
Granted, I have not tried to use emacs once the jit landed in 28 (or was it 29?). But it's something I really would really like to use since instead of having a different application for irc/mail/etc it could all just be emacs.
It been the main pain point for addung smarter autocomplete for years now.
However, lots of packages simply don't use these affordances.
Also, for LSP, there's additional challenges since lots of json needs parsing for each request, but IIUC Emacs can't currently process the messages to/from the server while the UI thread is busy (the LSP server can do lots of work while UI is busy, but the communication is stalled until UI is done). Though it seems things will be improving there, hopefully this'll get upstreamed soon: https://www.reddit.com/r/emacs/comments/ymrkyn/async_nonbloc...
I've read similar experiences from people all around the net, but my linux machine is also a bit more powerful than my macbook, but honestly not enough to explain the worlds of difference between the two.
Nevertheless, on both machines I've noticed a substantial speedup with the JIT you've mentioned, so maybe give it another try?
Emacs is not as snappy obviously. But it doesn't lags either. It's just not fast.
I’ve fallen into something of a cycle of adding packages until I’m annoyed by things breaking which results in me cutting back down to the basics.
I’m always amazed, once I get back to bare emacs and mostly elpa packages: everything works so well.
You either start trying to cram every possible task into that tool or try to find other software that was developed specifically for users of that tool (eg: Nyxt and Qutebrowser).
It feels like a very natural thing to do at the time even if it sometimes results in subpar results like what you're describing. I've personally declared "Emacs bankruptcy" multiple times and even go through periods of completely changing workflows if I get annoyed enough.
Same for computers at large. Let parents or kids install whatever, and expect woes.
Emacs can feel worse, in this regard; but, I for one love how open it is to extend. Literally a defun and you've extended it.
Which is how all (or at least most) of our computing systems should work. The inability to easily extend programs is what leads to the "need" to replace them so often with other programs that satisfy unmet needs or capabilities. Which ends up mostly creating churn, not value or utility.
Sorry, but it has to be said. Using a more sane language would cut down on the bugs and dependency problems in Emacs in a huge way.
P.S. Been using Emacs for over 25 years.
But unlike JavaScript (and Node.js), I don't know of anyone who uses Emacs out of the belief that Emacs Lisp is a language with which they should be building large-scale applications. It is strictly a client-side language and it is used as such.
In fact, Emacs Lisp is actually a pretty good client-side language. Not that it is perfect, but I find it more enjoyable to use than JavaScript.
Personally I would also think that a standard OOP system would be useful.
I can't imagine the maintenance of a Lisp system where several ten thousand names are flat in one namespace. For example: there is no way to browse those just looking at names with prefix parts. Textual name prefixes are a poor substitute for a proper "first class" namespace system. What parts of the symbol name are actually a prefix?
"CL-CADDAR" -> that means that I can't load any CL source code into Emacs, because every operator has been renamed. What? There is a subset of Common Lisp in GNU Emacs, but with all operators and variables renamed?
40 years ago Zmacs and the surrounding libraries on a Lisp Machine were already better structured.
> cl-defstruct or eieio
It's one thing to have features in a language as add-ons and actually having them integrated into the core. The whole optional CL feature & naming debacle shows that there are serious disconnects between developers and the leaders.
Not really sure what you mean. These are not "add-ons" any more than standard libraries are add-ons to other languages. They are fully integrated into core of Emacs, and has been that way for decades already. The naming situation might imply otherwise, but "cl-" namespace is by no means a second class citizen and I think there are practical value in keeping that naming scheme. In any case they are pervasively used both internally and in the community.
does not look like it is fully integrated into the core.
> I think there are practical value in keeping that naming scheme
To prohibit reuse of existing code? Where is the practical value? If Emacs Lisp had a namespace mechanism, this would be no topic and nobody would argue keeping a strange naming scheme, where operators are named incompatibly to the language where they were coming from.
Let's define most of Scheme features, but rename all the operators. That's really really strange to argue... I makes the reuse of millions of lines of existing code impossible from day zero.
1. The implementations of many functions are subtly different anyway, much like you can't expect Ruby's string join to work the same as Python's string join, down to an identical argument order and everything. That would be crazy to expect, right? You also can't do that kind of thing between Scheme and Common Lisp for what that's worth.
2. Even if you wanted to do this, the name of the function would be the easiest part of the migration: it takes one round of search-and-replace. So the namespacing is not the problem, and it's barely a problem at all.
I'm not really understanding you, maybe. Why would you expect Elisp to be able to run CLisp code verbatim? And why would you ding a language for its inability to fulfil such an uncommon use case?
Just go into a different namespace and load the code. The Lisp Machine I use has several different dialects of Lisp in one image. I can tell what dialect to use and it reads and evals code from that dialect. I can have two REPLs for different Lisps running side by side in one Lisp world, where I can call all operators from all other dialects.
That's basically also what was imagined for a GUILE-based GNU Emacs: it would run all of Emacs Lisp, but would also additionally understand Scheme.
> You also can't do that kind of thing between Scheme and Common Lisp for what that's worth.
Sure I can. Here I have loaded SCHEME into Common Lisp. The namespace is called SCHEME.
I'm in the CL-USER namespace:
CL-USER 8 > (scheme::define (scheme::foo1 x) (+ x 22))
foo1 defined.
CL-USER 9 > (scheme::foo1 20)
42
Now I switch over to the SCHEME namespace, where I can use the SCHEME operators like DEFINE without prefix: CL-USER 10 > (in-package "SCHEME")
#<The SCHEME package, 774/1024 internal, 0/16 external>
SCHEME 11 > (foo1 20)
42
SCHEME 12 > (define (foo2 a b) (+ a b 22))
foo2 defined.
SCHEME 13 > (foo2 9 11)
42
> the name of the function would be the easiest part of the migration: it takes one round of search-and-replace. So the namespacing is not the problem, and it's barely a problem at all.I'm not just talking about migrating code by converting it. I'm also talking about using the same code from one file.
> And why would you ding a language for its inability to fulfil such an uncommon use case?
It's only uncommon because you are not used to it. In earlier times even very complex source code was shareable between similar Lisp dialects.
If one adds to a Lisp lots of operators from a slightly different dialect, then it would be useful to do it in such a way that the dialect is integrated in a way that original source code written in that dialect can be shared with only a minimum of work.
Still, I don't want to just turn to nitpicking the examples. I asked, you gave. I'll think on those some.
I stand by my assertion that the abstractions are good for what emacs needs. As evidenced by how well it does keep up, all told. Does it do as well as a staffed resource to build some resources? Probably not. More, it is unlikely to ever be able to make a feature that nothing else can do. By virtue of it being open. If something is amazing from it, others can emulate it.
But, the amount of synergy between modules speaks volumes. Tramp alone is quite amazing at how many modes "just work" with it. With no prior planning on having to expose internals or special methods.
I also confess I expected threading to be mentioned. Another thing which I have seen cause as many errors as it typically helps. Effectively the "goto" of application development. Often best avoided, but also often required.
I would think that each Zmacs instance from 40 years ago already ran in its own thread.
Happy to know where I'm mistaken there. And I've certainly seen places where a blocking call can be annoying. Usually creeps up into a place that was fine at first. Org mode source execution is a good one. For the vast majority of stuff I do in those, I'm fine that it blocks while it gives me the results. Then I'll kick off one block that I should have added the async flag to, but just didn't.
My Lisp Machine emulator for Symbolics Genera is still responsive for the same code snippet, entered in a Listener window.
Edit: For amusement, I was trying to see how bad it could be, so I made a loop to get the 90000th fib. Which, wasn't enough to see here. Hard to really appreciate how fast computers have become.
But in a Lisp application to not be responsive at all is kind of rare. Most Lisp application runtimes will be able to process interrupts and/or switch "green threads" or "native threads".
Strongly disagree. With lexical bindings it's on par with contemporary strongly typed dynamic languages like python. It does even have fancy pattern matching with pcase library built in, plus lots of fancy stuff for editing like thing-at-point.
every single game with 'mods' has the same issues that the vast majority of extensible applications have.
the core developers (hopefully) care and understand about the cost of a cycle, whereas the mod/extension developers tend to care only about how their addition works and expresses itself to the user.
the mod/extension developers (generally, not in the case of foss projects) usually lack the scope to understand how their coding decisions affect the rest of the code base, or in the worst cases they lack the understanding needed to optimize something to the point of usability -- so they achieve their small purpose by any means possible, often times in fairly brutish manner, which kills app performance all together.
Dependency hell is very real and doesn't just affect Emacs. I simply version my entire Emacs (back since when Mercurial was a thing) config so any SNAFU that'd happen when I try a new package is one checkout away: I just reset to the last known good state and call it a day (for that package).
I've got about 3 000 lines of custom elisp code and everything works fine.
I don't disagree that bare Emacs and Elpa works well. Now that use-package is shipped with Emacs I eventually switched to it. Took a while but it's been smooth sailing.
I really heartedly recommend people to version their entire Emacs config in Git. Some shall go further and recommend to version your entire home directory for that matters. Or to use something like Nix.
I'd say any of these options is fine as long as "going back to the last working config" is one command away.
;; -*- eval: (git-auto-commit-mode 1) -*-
For the win.The point here is less "hey, Emacs has a dictionary!" (I'm sure many/most editors do!), more "hey, Emacs has a lot of use cases built in and they're easily discoverable." It's a great platform with a lot of care put into it over the years by different people, and if you come to it with the perspective of "it's just an editor" you'll be missing out.
Also the Emacs Manual and the Emacs Lisp Manual, which come with Emacs, very thoroughly document the Emacs extension interfaces.
Emacs also has comprehensive and high quality docstrings on functions and variables. I find them to be much more useful than in most other languages. You can very often get by just reading the docstrings.
And finally don't be afraid to look at the source. Bind find-function and find-variable to some convenient keys.
For those who are new to Lisp or want a refresher the Elisp Intro is great too: https://www.gnu.org/software/emacs/manual/eintr.html
Start simple. Find a personal itch to scratch, write some interactive functions that you can bind to keys. Or a hook to make something work way you'd prefer.
for instance, I did it for "(list" and found:
DEFUN ("list", Flist, Slist, 0, MANY, 0,
doc: /* Return a newly created list with specified arguments as elements.
Any number of arguments, even zero arguments, are allowed.
usage: (list &rest OBJECTS) */)
(ptrdiff_t nargs, Lisp_Object *args)
{
register Lisp_Object val;
val = Qnil;
...At least I have learned a lot from reading how these things fit together in the code, and occasionally replacing a definition entirely or creating advice around it.
It's a very easy environment to do so in, because the documentation is automatically linked to the relevant source code, so you never have to get stuck at something because you don't know what it does under the hood.
After a while of using both emacs and vim text editing, I found the vim way much easier for me. I used emacs with "evil mode" (vim keybindings) for a long time, but I wasn't using all of the other features the author here speaks about. So I found it easier to run Neovim alone instead of the extra complexity of getting emacs to behave like vim.
Here are some examples:
- Extract class / method / function (takes a piece of code and converts it to a class/method/free-floating function, while detecting all context dependencies and turning them to parameters or fields; also generates the proper constructors to populate those fields; and calls the right constructors/methods passing those parameters from context)
- Extract parameter / field (takes a local variable and makes it a parameter/field, and identifies all callers to propagate a value)
- Versions of the previous extractions that can go through a deeper call stack, automatically propagating along all functions along the way; essentially identical to using the same thing repeatedly, but in a single step
- Data flow to/from here (takes a variable and tells you something like 'the value here is coming from this parameter, which was populated from that field, which is assigned to in these two places; in the first place, it is assigned from this IO function; in the second place it is set to the value of this parameter which is populated from this constant; for "from", it is doing the same, but for all downstream uses of this value)
LSP itself certainly doesn't support this, though they can probably be built on top of it with some effort. For that matter, I also don't think VSCode supports them, though I have used Emacs far far more than that.
Of course Emacs has none of it. Through a combination of various extensions and plugins of wildly varying quality, and through increasingly arcane config files you can have some semblance of what an IDE offers, but definitely not even close to "all of it".
> through ... various extensions and plugins of wildly varying quality
Most Emacs plugins that I've seen are higher quality than most professional codebases I've seen.
> through increasingly arcane config files
Things are getting better not worse, so they are _decreasingly_ arcane config files. And Doom Emacs or Spacemacs make this dead simple to setup. This is no longer a valid issue.
I ended up moving to IntelliJ after being a long term Eclipse user and then using Emacs for about a year. I miss the keyboard-driven environment in Emacs and the more parsimonious keybindings, but IntelliJ is better as an IDE. Still use Magit though.
You don’t have to master Elisp at all to use Emacs, I have written very little Elisp. However I did use a distribution (Prelude, then Doom Emacs) which did a lot of the heavy lifting in setting up my initial environment - YMMV if you go in with vanilla Emacs and then edit your init.el until you find a working configuration for your needs.
* it's much, much more lightweight than IDEs like IntelliJ and VSCode.
* it supports every obscure language I like to try, not just the popular ones the IDE vendor has interest in supporting (third-party plugins for other IDEs tend to be pretty poor, IMO), and adding your own "macros" for new languages is very easy.
If you have a very powerful laptop with a lot of RAM and don't mind only using that for programming, and you only use languages that are well supported for your IDEs, then I don't think you would like emacs. Otherwise, it's great to have it!
For syntax highlighting and other syntax related features yes. But I often felt that it was a pain to get more involved features like debugging to work. I don't remember what the story was for automatic refactoring. I don't remember that working.
When I started programming, Turbo Pascal was all the rage, I then used Borland C/C++ IDEs. I saw various incarnations of Microsoft's Visual Studio come and go, get redone and rewritten. Every microcontroller vendor seems to try to ship their own IDE for some reason. All these IDEs come and go, and your customizations (or extensions) are lost.
In that same time, Emacs has stayed, and while it is being actively developed all the time, you can have a single IDE that works over a time span of 25 years or more. Parts of my init.el (Emacs initialization file) are from 1993.
Like I learnt vi originally because it was the only text editor on an air-gapped machine (since it had to connect to loads of obscure equipment) used for setting up psychology experiments in a lab I was an intern in.
I then used it on an Intel Atom 11" netbook for years as a student (I could only have one app open on a workspace at a time - everything had to be full-screen).
And then used it loads over SSH when working with a remote desktop and build server at a FAANG.
Both Emacs and Vim are so versatile in that respect.
I'd be curious to know what are these benefits. I traditionally prefer specialized tools for different purposes, so would be curious to know what others prefer about the Emacs-only life :)
The benefit is that, traditional process based boundary forces you to use IPC mechanism for combining different tools, e.g. unix pipes. This is fine for many things, but your communication medium is usually still a stream of bytes with no structure. Unless what you want can be achieved by simply combining two or more tools, when you write bespoke tools, you end up doing serialising and deserialising data over and over again just to send through pipe.
In Emacs all "plugins" reside in same process space, so they aren't handicapped by requirement of structure-less IPC. You can simply write functions that work on each other's structured data. This is more pronounced in case of TUIs such as ncurses programs (as opposed to CLI programs), they can't be composed or combined with each other easily, but in Emacs that's not a problem because underlying data layer remains accessible all the same. Overall, the mechanism of composing multiple specialised tools to produce gestalt effect is arguably more streamlined in Emacs, not less.
On the flip side, this homogenous ecosystem comes at the expense of not having an array of languages at your disposal like in unix. But tbh elisp is a fine general purpose language, so that's not as big a problem as you might think. There are other concerns like security, plugins being able to peek into another's data is one of seminal reasons why OS process as boundary is a thing.
Nowadays though, with a few popular app platforms running on numerous operating systems, there is a clear distinction between OS and app platform.
Emacs is an app platform for client-side applications.
Yes, exactly. That app platform provided a system-independent UI for text- and editor-based apps.
But I would think that even in the 80s/90s there were a bunch of other examples for app platforms.
I'll say it: the browser is an OS, sue me.
[1] we always could of course, it was just not mainstream