unrepl

discussing specification of an edn-based repl and its implementations.
cgrand 2017-04-12T08:43:57.836843Z

grmbl a “real” repl in (bootstrap) cljs needs a lot to be sorted out.

cgrand 2017-04-12T08:45:04.853051Z

• input abstraction • bindings handling

cgrand 2017-04-12T08:46:59.880744Z

bindings, var-set support would be the MVP (minimum viable patch ;-))

thheller 2017-04-12T08:52:09.957252Z

@cgrand I don't think the normal REPL model would be all that useful in JS

thheller 2017-04-12T08:52:29.962467Z

as most operations will be async and the normal model really relies on sync and blocking

cgrand 2017-04-12T08:53:37.978484Z

most IO are async, true

cgrand 2017-04-12T08:54:45.995008Z

what model do you propose?

thheller 2017-04-12T08:55:00.998584Z

I have no idea

thheller 2017-04-12T08:55:12.001334Z

I treat it as RPC at the moment

thheller 2017-04-12T08:55:46.009941Z

just faking a REPL on top of it in the CLJ side

thheller 2017-04-12T08:55:59.012921Z

the JS side is pure RPC

cgrand 2017-04-12T08:57:11.030771Z

I’m focusing on selfhosted cljs atm so there’s no CLJ side

thheller 2017-04-12T08:58:13.046153Z

well call it compiler and eval sides

cgrand 2017-04-12T08:58:13.046265Z

and the JS side is not pure RPC because of the async nature: when the RPC returns processing may still be going on.

thheller 2017-04-12T08:58:39.053110Z

yes but you get a Promise or something usually

thheller 2017-04-12T08:58:50.055918Z

(I don't handle *out*)

thheller 2017-04-12T09:01:30.099028Z

this is the JS side of the node REPL .. it is connected to a websocket that gets messages from the server (CLJ)

thheller 2017-04-12T09:01:59.106449Z

it takes the msg, calls (js/eval ...) and sends the result back

thheller 2017-04-12T09:02:56.121270Z

guess thats not RPC since the server doesn't call it

thheller 2017-04-12T09:03:34.130982Z

but each :repl/invoke msg produces one :repl/result msg

thheller 2017-04-12T09:04:10.140266Z

but the client can decide how to handle that message, ie. the browser impl is different

cgrand 2017-04-12T09:05:49.166586Z

Ok but this has nothing to do with the hurdles that I have.

thheller 2017-04-12T09:08:23.204565Z

tried to use it as an example of how I think any REPL in JS will look really

cgrand 2017-04-12T09:08:54.211952Z

To summarize: there’s no generic way to write a repl in selfhosted CLJS because: 1/ there’s no agreed upon *in* (or equivalent), so no R 2/ there’s no agreed upon eval (planck has one), so no E bonus/ bindings conveyance requires hack unless you want dynvars (print-fn ns etc.) to leak from one repl to the other

thheller 2017-04-12T09:09:40.223321Z

1) browsers do not have an *in* at all

cgrand 2017-04-12T09:09:48.225204Z

(for the last point, start lumo in socket server, open two repls, changing ns in one, change the ns in the other)

thheller 2017-04-12T09:10:11.230699Z

2) there is JS eval so you need to define C for compile

thheller 2017-04-12T09:10:29.235365Z

RCEPL

cgrand 2017-04-12T09:10:57.242056Z

no: E is compile+js/eval

thheller 2017-04-12T09:12:25.263955Z

RCEP_L_ bold happens on the "server" side

thheller 2017-04-12T09:12:43.268445Z

well that didn't work

thheller 2017-04-12T09:12:56.271356Z

RC+L CLJ EP JS

cgrand 2017-04-12T09:13:05.273668Z

1) I’m not considering browsers

thheller 2017-04-12T09:13:52.284712Z

you are not considering non-selfhost

cgrand 2017-04-12T09:16:10.317667Z

not at the moment, one step after the other

thheller 2017-04-12T09:16:47.326950Z

well my suggestion would be to start with normal CLJS not self-hosted CLJS

thheller 2017-04-12T09:17:06.331575Z

anything that works with normal can work self-hosted, not true the other way around

cgrand 2017-04-12T09:27:47.490288Z

I disagree on “anything that works with normal can work self-hosted” because most of a normal CLJS repl is CLJ and uses blocking IO

thheller 2017-04-12T09:28:39.503462Z

well you can write the CLJ side async, so yes "anything" is incorrect

thheller 2017-04-12T09:29:29.515805Z

but you have to account for the 2 runtimes issue

cgrand 2017-04-12T09:29:41.518669Z

selfhosted is easier than normal because there’s not two envs to deal with, it’s closer to CLJ (minus sync IO) but needs some gaps to be filled.

thheller 2017-04-12T09:29:54.521868Z

selfhosted is also very limited and not very useful for big apps (and not an option for browser targets)

cgrand 2017-04-12T09:30:13.527173Z

I wouldn’t bet against it in the long run

thheller 2017-04-12T09:34:32.591440Z

hmm dunno ... not too optimistic for node.js as a runtime. It is horrible.

thheller 2017-04-12T09:35:12.600657Z

so I really wouldn't write anything server side in pure CLJS not because of self-hosted but because of JS

cgrand 2017-04-12T09:36:44.623109Z

9 years ago I started working with Clojure because I got badly burnt doing server-side JS 😄

thheller 2017-04-12T09:37:12.629868Z

and you want to go back? 🙂

cgrand 2017-04-12T09:39:56.668622Z

Vendetta 🙂

thheller 2017-04-12T09:41:26.689896Z

no threads still so not much has changed

cgrand 2017-04-12T09:41:50.695600Z

to make things worse it had threads (Rhino)

cgrand 2017-04-12T09:42:27.704331Z

(threads + JS = 💣 )

thheller 2017-04-12T09:51:39.834842Z

yeah dunno, I don't get how you could write a serious server application in a runtime that was strictly built and optimized for the browser

thheller 2017-04-12T09:54:50.879343Z

heck I spent soo much time even trying to get my browser apps performant enough to be acceptable and that is just one user at a time.

pesterhazy 2017-04-12T10:18:04.202939Z

@cgrand, well node.js has streams, which do resemble *in* and *out*

pesterhazy 2017-04-12T10:19:06.215914Z

but bindings are no good if they don't survive across events

cgrand 2017-04-12T10:19:37.222655Z

yeah but they are specific to node

cgrand 2017-04-12T10:20:24.232970Z

*out* and *err* are already covered by *print[-err]-fn*

pesterhazy 2017-04-12T10:20:56.239931Z

well, only if you can print synchronously, right?

pesterhazy 2017-04-12T10:22:01.254289Z

but yeah typically you can print synchronously, even in browsers

cgrand 2017-04-12T10:22:45.263864Z

that’s why in evented-reader I introduce a Stream abstraction to create *in*. Then the author of the root repl may provide an impl

cgrand 2017-04-12T15:18:08.474806Z

Ok the bridge is working.

cgrand 2017-04-12T15:19:29.507475Z

(nrepl-bridge/repl & nrepl-args) recreates a pair of stdin/stdout to a clojure.main/repl on top of nrepl

cgrand 2017-04-12T15:29:26.753956Z

; the following example upgrades the running repl to mirror the replized nrepl :-)
  (mirror (repl :port 62005))

cgrand 2017-04-12T15:31:38.811032Z

So now we can work either with a socket repl or a nrepl (as long as the client is written in Java…)

1😮
cgrand 2017-04-12T19:31:31.226591Z

Perverse idea: upgrade a repl to nrepl…

dominicm 2017-04-12T19:34:38.290555Z

if you supported bencode, all would be fine

richiardiandrea 2017-04-12T19:45:29.511009Z

is there an nRepl protocol spec somewhere?

dominicm 2017-04-12T19:45:46.516571Z

the readme is it pretty much

dominicm 2017-04-12T19:45:54.519385Z

The spec isn't bit

dominicm 2017-04-12T19:45:57.520450Z

*big

dominicm 2017-04-12T19:46:12.525179Z

the spec defines that messages going in must be a map with an op key.

dominicm 2017-04-12T19:46:50.538538Z

when an op has been handled, a message must be sent over that transport with a :status including "done" in the result

dominicm 2017-04-12T19:47:08.544003Z

the bencode transport is just a transport mechanism for those maps.

dominicm 2017-04-12T19:47:15.546305Z

Common ops are included in tools.nrepl

dominicm 2017-04-12T19:48:14.565702Z

if a message has an :id it should come back with an :id (it's possible that this is done by merging into the incoming map, but I'm not certain)

richiardiandrea 2017-04-12T19:48:43.575915Z

uhm, seems quite easy to replicate indeed

cgrand 2017-04-12T19:49:18.587451Z

Yeah but then there's the middlewares

dominicm 2017-04-12T19:51:10.625867Z

@cgrand The middleware is really just an implementation detail of tools.nrepl. I'm "out there" and I have 4 middlewares in my profile.

dominicm 2017-04-12T19:51:32.633563Z

I suppose 5 if you count piggieback for cljs.

dominicm 2017-04-12T19:56:02.726400Z

Middlewares are based on dependency ordering using a topological sort. It's not super easy, I'll admit. But it isn't crazy (in fact, it's already done!)

dominicm 2017-04-12T19:56:09.728879Z

https://github.com/stuartsierra/dependency makes it easier

cgrand 2017-04-12T20:10:22.025517Z

Ok but don't count me in for the implementation.

dominicm 2017-04-12T20:11:12.041922Z

heh.

dominicm 2017-04-12T20:11:33.049422Z

@cgrand you're extremely productive. I wanted to ask how you approach problems & get stuff done.

cgrand 2017-04-12T20:19:25.207151Z

The secret is having some accounting or paperwork to do :-)

cgrand 2017-04-12T20:22:03.260649Z

Seriously I don't consider myself as extremely productive. I'm productive by bursts when ideas have been on the back burner (or hammock) long enough

cfleming 2017-04-12T23:04:28.917849Z

I agree with that, I tend to ruminate on a problem for ages and spend a long time investigating it, and then have short bursts of activity when I actually do the work.

cfleming 2017-04-12T23:04:43.920684Z

And accounting and paperwork does indeed also help 🙂