Fork me on GitHub
#unrepl
<
2017-04-12
>
cgrand08:04:57

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

cgrand08:04:04

• input abstraction • bindings handling

cgrand08:04:59

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

thheller08:04:09

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

thheller08:04:29

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

cgrand08:04:37

most IO are async, true

cgrand08:04:45

what model do you propose?

thheller08:04:00

I have no idea

thheller08:04:12

I treat it as RPC at the moment

thheller08:04:46

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

thheller08:04:59

the JS side is pure RPC

cgrand08:04:11

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

thheller08:04:13

well call it compiler and eval sides

cgrand08:04:13

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

thheller08:04:39

yes but you get a Promise or something usually

thheller08:04:50

(I don't handle *out*)

thheller09:04:30

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

thheller09:04:59

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

thheller09:04:56

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

thheller09:04:34

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

thheller09:04:10

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

cgrand09:04:49

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

thheller09:04:23

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

cgrand09:04:54

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

thheller09:04:40

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

cgrand09:04:48

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

thheller09:04:11

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

cgrand09:04:57

no: E is compile+js/eval

thheller09:04:25

RCEP_L_ bold happens on the "server" side

thheller09:04:43

well that didn't work

thheller09:04:56

RC+L CLJ EP JS

cgrand09:04:05

1) I’m not considering browsers

thheller09:04:52

you are not considering non-selfhost

cgrand09:04:10

not at the moment, one step after the other

thheller09:04:47

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

thheller09:04:06

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

cgrand09:04:47

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

thheller09:04:39

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

thheller09:04:29

but you have to account for the 2 runtimes issue

cgrand09:04:41

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.

thheller09:04:54

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

cgrand09:04:13

I wouldn’t bet against it in the long run

thheller09:04:32

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

thheller09:04:12

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

cgrand09:04:44

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

thheller09:04:12

and you want to go back? 🙂

cgrand09:04:56

Vendetta 🙂

thheller09:04:26

no threads still so not much has changed

cgrand09:04:50

to make things worse it had threads (Rhino)

cgrand09:04:27

(threads + JS = 💣 )

thheller09:04:39

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

thheller09:04:50

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.

pesterhazy10:04:04

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

pesterhazy10:04:06

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

cgrand10:04:37

yeah but they are specific to node

cgrand10:04:24

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

pesterhazy10:04:56

well, only if you can print synchronously, right?

pesterhazy10:04:01

but yeah typically you can print synchronously, even in browsers

cgrand10:04:45

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

cgrand15:04:08

Ok the bridge is working.

cgrand15:04:29

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

cgrand15:04:26

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

cgrand15:04:38

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

cgrand19:04:31

Perverse idea: upgrade a repl to nrepl…

dominicm19:04:38

if you supported bencode, all would be fine

richiardiandrea19:04:29

is there an nRepl protocol spec somewhere?

dominicm19:04:46

the readme is it pretty much

dominicm19:04:54

The spec isn't bit

dominicm19:04:12

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

dominicm19:04:50

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

dominicm19:04:08

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

dominicm19:04:15

Common ops are included in tools.nrepl

dominicm19:04:14

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)

richiardiandrea19:04:43

uhm, seems quite easy to replicate indeed

cgrand19:04:18

Yeah but then there's the middlewares

dominicm19:04:10

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

dominicm19:04:32

I suppose 5 if you count piggieback for cljs.

dominicm19:04:02

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!)

cgrand20:04:22

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

dominicm20:04:33

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

cgrand20:04:25

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

cgrand20:04:03

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

cfleming23:04:28

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.

cfleming23:04:43

And accounting and paperwork does indeed also help 🙂