Continued progress porting Emacs to Rust
db48x.net
db48x.net
> For users, I hope Remacs will be faster (it's easier to optimise), more robust (we have stronger type checks and the ability to add unit tests), better documented (see #262) and somewhat more featureful (we have some ideas for solving the dumper problem that would allow users to dump their instance as an image) than GNU Emacs.
> I think we will get problems when the current generation of emacs devs retire and there's a better chance that emacs will survive if we try to make it more appealing to young developers. Rust seems to be a good option.
The main reason my emacs is painfully slow is that most elisp code blocks. Stuff like hitting tab for auto-completion might perform a blocking query from a language server hanging emacs for multiple seconds. Opening a file tries to start a language server and blocks the editor in the process. Etc.
Making emacs itself faster won't make the experience of working with emacs any better.
Note that multithreading is now in Emacs master, and some core packages (e.g., Tramp, which used to block when opening a remote file) have already been updated to make use of it, so starting with the next major release things will be improving on this front.
I agree that it's not the panacea though, Emacs would benefit from using a more threaded or event-oriented programming model for many things.
Though I only use auto-complete on emacs commands, so maybe I've just missed it.
In that case, they should rewrite the Lisp code in JavaScript.
Yes, I'm being sarcastic.
More importantly, they write:
static struct Lisp_Objfwd o_fwd;
"... creates an (uninitialized) static variable called o_fwd". No. C static variables are implicitly initialized to zero of the appropriate type, in this case, apparently a struct containing only a null pointer. This also means that their unsafe {
#[allow(const_err)]
static mut o_fwd: ::hacks::Hack<::data::Lisp_Objfwd> =
unsafe { ::hacks::Hack::uninitialized() };
"a lot more typing to get a proper uninitialized value in a Rust program" is just useless voodoo.Can you elaborate on “as good as uninitialized”?
In the internals of TXR Lisp, I used a null pointer to represent the symbol nil, with all the useful semantics that follows. If an object containing Lisp values is initialized to zero, those values are nil.
However, this is not a Lisp value; it's a pointer to one. Specifically, it's a pointer to memory set aside to store a specific Lisp variable's value. Leaving it zeroed makes no sense, because eventually someone is going to store a value in there and it'll have to be allocated anyway. Better to do that all in one large block, rather than a thousand tiny ones. Even if we wanted to lazily allocate these, we can't leave a simple Rust reference (or pointer) null past the end of the unsafe block.
Rust does have an Option type, and if you use it on a type that isn't nullable, then the compiler will use the zero value for None variant and all other values for the Some. Since references can never be null, an Option<&T> will always take up the same amount of space as a &T; there's no additional overhead. At some point, when enough of the C code is ported to Rust, I'm sure we'll start using this to represent all Lisp values and a Lisp nil will always be a Rust None.
So make it an Option, and get rid of the unsafe block altogether.
Which one? It has multiple.
First, there is storage duration:
C99 6.2.4 "There are three storage durations: static, automatic, and allocated."
Variables with external linkage defined at file scope are static in the sense that they have static storage duration; it is not incorrect to call them static variables, though a bit unusual. If they have external linkage, it's more common just to call them globals.
The static storage class specifier keyword used at file scope causes a name to have internal linkage. In a block scope, it requests the above static storage duration.
The one that was entirely clear from context: Linkage.
DEFUN ("atan", Fatan, Satan, 1, 2, 0,
Hah I couldn't read that with a straight face!I think it is GuileEmacs I am remembering.
I hope to two efforts are compatible.
If remacs manages to reach the point where you can use it to replace emacs in-place without any breakage while bringing better performance and more stability it will be a tremendous success IMO.
I wouldn’t imagine that the two efforts are compatible, because they are both efforts to rewrite the Emacs Lisp engine in another language, one in Rust & one in Guile Scheme. It’s possible that one might be able to call over to the other, through its CFFI.
I’d like to see Emacs rewritten in Common Lisp, and so I’d prefer a Rust engine to a Guile engine: Rust is a static language, and a Rust engine is unlikely to lead to Rust-extensible Emacs code, while a Guile engine is likelier to lead to Guile-extensible Emacs code, which is completely the wrong direction IMHO.
What does "incompatible" mean here? Incompatible with the Scheme language reports, or incompatible with other Schemes' extensions?
Edit: Guile won't be used, because of the burden of contributing. https://github.com/Wilfred/remacs/issues/66#issuecomment-273...
I assume the Rust-based emacs would do the same thing?
Emacs will change how you think about programming.
Emacs is an incremental programming environment. There's no
edit-compile-run cycle. There isn't even an edit-run cycle. You can
execute snippets of code and gradually turn them into a finished
project. There's no distinction between your editor and your
interpreter.
I'm assuming what it means is "Emacs will change how you think about programming Emacs Lisp". Which is a rather narrower proposition, and much less of an incentive to switch, since I doubt many non-Emacs users are particularly interested in programming Emacs Lisp.The difference is what it means for your repl. You can trivially attach your repl to a running process. So you change an expression, tell emacs that you'd like that to be sent to the repl, and because the repl is attached to your running process everything updates immediately.
I put this together years ago: https://www.youtube.com/watch?v=W2NJppeLsN8
It does a pretty terrible job of demonstrating what this might mean for something like web development where the feedback circle is usually as bad as it can be.
Lisp changes how you think about programming. Emacs gives you the shortest path to a code/test feedback loop.
Once you’ve been there, you’ll probably never want to go back. My only wish is that emacs were written in an even better language than elisp (like Common Lisp).
There are a lot of bad things in CL too, unfortunately. I wonder if a Lisp will become really popular in the near future. Maybe Racket?
Common Lisp is actually quite a bit more advanced out of the box than Emacs Lisp: lexical binding, excellent error handling, good support for compilation, extensive object-oriented features, it has multiple implementations with independet code bases, implementations with threading, ...
CL has been used to develop Emacs editors already.
But the thing is a non-starter. There are a few million lines of Emacs Lisp for a specific editor, which nobody will rewrite.
I’d like to see an Emacs with a Common Lisp core, and an elisp execution engine to run all the legacy elisp code. https://github.com/blindglobe/clocc/blob/master/src/cllib/el... looks like a decent first start, although it supports an older version of elisp.
Someday if I have the free time I’d love to spend time working on such a thing. Maybe when I’m retired!
sure, but you need to support legacy software, too. Which is most Emacs Lisp ever written.
In fact, the original Lisp machine eventually supported Common Lisp as well as the original Lisp Machine Lisp. You could write any individual function in either language, and call from one to the other transparently.
I have no idea how easy it is and I have seen no attempt to do that (running the existing Elisp code without modification on top of a CL runtime). If it would be easy, I'd expect it to be done already.
The https://www.cliki.net/CL-Emacs page seems to of no help...
Do you know of any attempt demonstrating how easy it actually is?
> In fact, the original Lisp machine eventually supported Common Lisp as well as the original Lisp Machine Lisp. You could write any individual function in either language, and call from one to the other transparently.
That was a major engineering effort - putting both languages side by side onto a single runtime.
But this is just me nitpicking about elegance.
But if we look around - most alternatives have their variants of keyword alternative mechanisms.
Racket: https://docs.racket-lang.org/guide/lambda.html
Guile: https://www.gnu.org/software/guile/manual/html_node/Coding-W...
Chicken Scheme: https://wiki.call-cc.org/man/4/Extensions%20to%20the%20stand...
> I doubt many non-Emacs users are particularly interested in programming Emacs Lisp
By definition, if you're programming Emacs Lisp, you're an Emacs user. Emacs is the interpreter.
That's not necessarily true. Guile supports Elisp as a language. You can write Elisp sans Emacs.
As languages go, I would say that Forth and Prolog also have this quality of expanding your frame of reference.