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 [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en