nrepl

https://github.com/nrepl/nrepl || https://nrepl.org
cgrand 2018-12-17T09:26:19.126700Z

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?

cgrand 2018-12-17T09:40:11.134700Z

@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

cgrand 2018-12-17T09:46:56.137700Z

summary reality is complex, RPC and streaming are ends of a continuum

bozhidar 2018-12-17T10:01:08.138800Z

Excellent summary!

bozhidar 2018-12-17T10:01:16.139Z

> Wouldn’t it be more sensible to prefer nrepl.core over clojure.tools.nrepl?

bozhidar 2018-12-17T10:03:25.141100Z

@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.

bozhidar 2018-12-17T10:04:05.141900Z

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.

👌 1
cgrand 2018-12-17T11:54:21.144300Z

I’m happy to report that datafy/nav is now supported by rich (unrepl) printing: https://github.com/nrepl/nrepl/commit/26e51fbca0dfba5a9ee247605445df7e58e83269

1
cgrand 2018-12-17T12:29:21.148700Z

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.

dominicm 2018-12-17T12:30:17.149300Z

Does this affect existing clients? How?

cgrand 2018-12-17T12:32:37.150400Z

unrepl printing is opt-in (set :printer to nrepl.elisions/printer on :eval)

eraserhd 2018-12-17T14:31:45.151500Z

@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.

cgrand 2018-12-17T14:34:04.151800Z

for some simple elisions, it sort of work

cgrand 2018-12-17T14:34:34.152400Z

I experimented with /1 /2 etc.

cgrand 2018-12-17T14:35:34.153200Z

they are not readable so won’t clash with clojure code

cgrand 2018-12-17T14:36:26.154300Z

..x are going to be tranformed by the compiler I think (because of the leading dot)

eraserhd 2018-12-17T14:36:41.154800Z

Ahh, I wasn't to worried about that. I was worried about needing to keep the numbers forever.

cgrand 2018-12-17T14:36:53.155300Z

(if they ccur in function position)

cgrand 2018-12-17T14:37:51.156200Z

indeed if you use vars, they are interned and you can’t knwo when to GC

eraserhd 2018-12-17T14:37:54.156300Z

you are right, hrmm

eraserhd 2018-12-17T14:38:09.156400Z

(re: .)

cgrand 2018-12-17T14:38:44.156800Z

or you can choose to keep the last N vars

eraserhd 2018-12-17T14:39:00.157500Z

right, and then you have unusable stuff in your history.

eraserhd 2018-12-17T14:39:17.158Z

but, I want it to work! :D

cgrand 2018-12-17T14:39:24.158200Z

at some point GC pressure may cause collection of elisions anyway

cgrand 2018-12-17T14:40:31.158800Z

click (or tab-navigate) to expand is a better ux if you can afford to

cgrand 2018-12-17T14:41:23.159600Z

with datafy/nav, many values may be littered with small affordances hinting that an alternate view is available

eraserhd 2018-12-17T14:44:06.161700Z

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!

eraserhd 2018-12-17T17:02:48.162600Z

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.

dominicm 2018-12-17T18:05:25.162800Z

They are.

dominicm 2018-12-17T18:05:34.163100Z

Why do you think they aren't?

cfleming 2018-12-17T19:21:20.163800Z

@cgrand Thanks! I agree that the main benefit of streaming REPLs is that they’re composable, but that definitely comes at a cost.

cgrand 2018-12-17T19:23:12.164600Z

@cfleming no they are not; see https://github.com/nrepl/nrepl/issues/45#issuecomment-444476311

eraserhd 2018-12-17T19:24:32.165900Z

@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.

dominicm 2018-12-17T19:25:56.166800Z

@eraserhd I don't understand the point you're making. Can you give an example?

eraserhd 2018-12-17T19:27:10.167300Z

I don't have a point, I want to understand abstracting clients from connections and sessions.

dominicm 2018-12-17T19:27:45.167700Z

@eraserhd what's a client in this context?

eraserhd 2018-12-17T19:28:04.168100Z

return of nrepl.core/client

dominicm 2018-12-17T19:35:56.169500Z

But you would call that from a separate process, not necessarily even the same network