As I was reading Drawbridge, I stumbled on:
(if (find-ns 'clojure.tools.nrepl)
(require
'[clojure.tools.nrepl :as nrepl]
'[clojure.tools.nrepl.server :as server]
'[clojure.tools.nrepl.transport :as transport])
(require
'[nrepl.core :as nrepl]
'[nrepl.server :as server]
'[nrepl.transport :as transport]))
Wouldn’t it be more sensible to prefer nrepl.core
over clojure.tools.nrepl
?@cfleming putting my thoughts together would take time and a small article. streaming pros: super simple model: 1 connection :: 1 repl :: 1 thread; can be taken over (powerful) streaming cons: tracking progress (see prepl and unrepl takes), mixed output streams (because of laziness, modern envs with more than 1 thread, err vs out etc.) (again unrepl and prepl both frame outputs, so their output is a stream of forms instead of a stream of characters); can be taken over (interfer with framing) RPC pros: 1 connection for everything; easy progress report (because framed input) RPC cons: thread management/serialization of evals; explicit lifecycle management; can not be taken over
summary reality is complex, RPC and streaming are ends of a continuum
Excellent summary!
> Wouldn’t it be more sensible to prefer nrepl.core
over clojure.tools.nrepl
?
@cgrand Probably. I didn’t think much about this, as it was supposed to be a temporary measure and now that leiningen ships nREPL 0.5 we can remove all the compatibility code.
Probably I’ll cut one more release of cider-nrepl that supports tools.nrepl and afterwards I’ll go over all the middleware/transport projects and drop this for simplicity’s sake.
I’m happy to report that datafy/nav is now supported by rich (unrepl) printing: https://github.com/nrepl/nrepl/commit/26e51fbca0dfba5a9ee247605445df7e58e83269
Obviously (as for elisions) it requires client-side ui.
A datafiable value is represented as #unrepl/browsable [plain-value browsable-value]
and to make this lazy the browsable-value
is elided.
For nav, it’s the same thing: if the datafied value is a map or a vector and is navigable then the map values becomes elided #unrepl/browsable
whose elision triggers nav
.
Does this affect existing clients? How?
unrepl printing is opt-in (set :printer
to nrepl.elisions/printer
on :eval
)
@cgrand I've been playing with the idea of not needing client side UI by binding variables to ..1 ..2 ..3 and so forth. Except I can't quite make the idea work.
for some simple elisions, it sort of work
I experimented with /1
/2
etc.
they are not readable so won’t clash with clojure code
..x
are going to be tranformed by the compiler I think (because of the leading dot)
Ahh, I wasn't to worried about that. I was worried about needing to keep the numbers forever.
(if they ccur in function position)
indeed if you use vars, they are interned and you can’t knwo when to GC
you are right, hrmm
(re: .)
or you can choose to keep the last N vars
right, and then you have unusable stuff in your history.
but, I want it to work! :D
at some point GC pressure may cause collection of elisions anyway
click (or tab-navigate) to expand is a better ux if you can afford to
with datafy/nav, many values may be littered with small affordances hinting that an alternate view is available
Anyway, I'm super excited to have this somehow baked in to my REPL. It solves quite a few problems for me, including 10,000 line exceptions in my primary app. So, thanks for working on it!
Hey, that brings up a question about the nREPL client API. Why have a split between connection and client? It doesn't seem like multiple clients are possible per connection.
They are.
Why do you think they aren't?
@cgrand Thanks! I agree that the main benefit of streaming REPLs is that they’re composable, but that definitely comes at a cost.
@cfleming no they are not; see https://github.com/nrepl/nrepl/issues/45#issuecomment-444476311
@dominicm I meant, to be clear, that it doesn't seem to add anything, AFAICT. There's not concept of client on the wire protocol, only session. And that's another layer of abstraction in the API.
@eraserhd I don't understand the point you're making. Can you give an example?
I don't have a point, I want to understand abstracting clients from connections and sessions.
@eraserhd what's a client in this context?
return of nrepl.core/client
https://nrepl.org/nrepl/usage/clients.html#_talking_to_an_nrepl_endpoint_programmatically
But you would call that from a separate process, not necessarily even the same network