Hi, After Rich's suggestion at the recent NYC meetup, I had a detailed look at inferior-lisp vs. Slime, and nREPL, read Chas' document, wrote a bit of code, tried to figure out the issues for myself; here are my conclusions on nREPL:
- In the Slime/Swank model, there is a single IDE that connections to N possible types of LISPs via a rich protocol (and a lot of corresponding work on the workflow/GUI side in Emacs in the various fancy Slime functions I discussed at the meetup). Emacs/Slime -> Clojure, sbcl, clisp, Allegro, etc. My understanding of nREPL is that it inverts the problem by making M different IDEs able to connect to one type of LISP VM (Clojure). Emacs, Eclipse, NetBeans, whatever, etc. -> Clojure One of the assumptions is that by keeping nREPL simple the various clients will send whatever necessary Clojure code they want in order to perform the same common tasks that the Swank protocol already describes. I think that this is touted to be "powerful" because you can eval anything you like, i.e., "just send it some clojure expression you want". But from my POV, it only serves to move the complexity from the server/VM (currently in swank-clojure and the protocol) to the client/IDE. I think this is wrong, because every single IDE client will have to adapt itself to the various changes occurring in the Clojure VM as it evolves. This is just creating M times the amount of porting problems (for each client). By keeping the complexity on the server, every IDE that speaks a common protocol (*) works between versions. One could argue that a rich client library could be included that provides similar functionality that is currently provided by swank-clojure, i.e. the problem is lessened, because all the clients now share the same client library, so you port over the client lib and recompile and that should be enouhg. But what language do you do this in? Clojure itself? Pure Java? What about the Emacs-LISP client? Then you have a problem of having multiple client libraries that need be ported. - I take another issue at nREPL: if someone is going to implement a request/response protocol that supports only generic requests (because the complexity should live in the client), why bother at all, why not instead just make it a really, really simple network REPL, without any protocol at all? e.g. all input means "eval", output is just output, no ids no nothing.... just a socket that you could connect to with telnet and have a repl right there, no protocol. telnet localhost 4005, type "(+ 2 2)" at the terminal, see "4" appear. That's it. I think it would be pretty straightforward to extend Emacs' inferior-lisp-mode to support talking to a socket like that instead of having to start a subprocess. This would give you "vanilla" communication with a live Clojure VM without having to start the VM from a parent process. I rather like this idea; it's the simplicity you currently enjoy with inferior-lisp, but over a socket; simple, can't break. IMHO if people will bother implementing a request/response protocol, why not just stick with a rich protocol like Swank's? It'll just be reinventing the wheel otherwise. - Another problem with Slime that turns people off is the weirdness in where the output goes. To detail the weirdness: 1. Return values get rendered in the Emacs minibuffer 2. stdout of the main thread goes to the *slime-repl* buffer 3. stdout of all the other threads go to the console of the VM, because they inherit System/out 4. Side-effects from converting return values to string (i.e., from lazy seqs, e.g., (map println (range 10))) appear in the minibuffer too, interspersed with the return values. I think a fair bit of that weirdness can be addressed easily: - I already coded a fix for (4) in my clone of swank-clojure. - (2) is normal, that's what you expect. - (3) can be addressed in 1.3 by setting up a suitable binding to override *out* so that child threads inherit that that instead of the default *out*. The stream object that would replace *out* to should send a swank message back to emacs to have the output printed in the repl. Note that this isn't going to work always; pure Java code running in child threads could still output to System/out, the console (is there any way to hijack System/out in Java? I spent 10 minutes on it, it looks like not). Also, nREPL and even the simplistic telnet-like networked repl would suffer from the same problem. - (1) could be changed by adapting swank-clojure to return the result as an output command from swank, and to always return 'nil' as the result. IMHO this could be an option to Swank--I personally find it neat to have two separate places to print stdout and the result of the expression, and the slime repl vs. the minibuffer provide that, but I can see how that's a little weird. Those changes would make Slime behave a lot more like inferior-lisp-mode; a lot less strangeness, one place for all output, the *repl* buffer. I'm curious to hear people's thoughts. I don't have a ton of experience with Clojure and I also might be misled regarding the aims of the nREPL project. What's bothering people with Swank's protocol anyway? In any case, I think it would be really cool to implement a simplistic networked repl and adapt inferior-lisp-mode to work with it (without a protocol), and fix the couple of warts in Slime so that at least output doesn't go to three different places. -- M. (*) Please note: I am aware that only Emacs supports the Swank protocol right now but I don't see why other IDEs couldn't support it too--it's just made up of LISP forms after all; in other words, if someone wants to replace the swank protocol by an equivalent one with a different encoding I don't really see the point. Anyway, for this discussion I'll assume emacs-rex is a suitable enough protocol; in fact, I think it probably is, because it has already proved itself with a large number of LISP environments, it has "history". In any case, that's a separate discussion. I think of emacs-rex as just "the protocol" and that other IDEs could implement it to talk with swank-clojure. -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en