This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # adventofcode (12)
- # announcements (1)
- # asami (18)
- # aws (1)
- # babashka (20)
- # beginners (80)
- # calva (11)
- # cider (10)
- # circleci (5)
- # cljsrn (2)
- # clojure (37)
- # clojure-australia (15)
- # clojure-europe (32)
- # clojure-nl (2)
- # clojure-uk (26)
- # clojured (7)
- # clojurescript (10)
- # clojurewerkz (3)
- # cursive (45)
- # data-science (12)
- # datomic (3)
- # emacs (8)
- # events (3)
- # fulcro (23)
- # graphql (5)
- # helix (3)
- # jobs (1)
- # jobs-discuss (1)
- # juxt (3)
- # lsp (12)
- # malli (4)
- # meander (4)
- # reagent (11)
- # releases (1)
- # shadow-cljs (28)
- # sql (35)
- # tools-deps (9)
- # xtdb (25)
I see. I'm probably not well-informed in the topic, I only based my initial comment on what I read in the article I linked
Cursive could do this, yes, since it implements a simple protocol over a socket REPL. However there are complications with that, as you might expect - each eval is then in a different thread and needs dynamic bindings propagated etc. Currently with socket REPLs the evaluations are strictly sequential, but once evals are in separate threads that’s no longer the case, and there is potential weirdness around that too. In general the idea with the socket REPL was to try to keep things simple, and I’m not sure whether that counts 🙂
Yeah, I prefer the mental model for sure. Unfortunately, a great deal of my work involves starting an infinite loop of some sort, and being unable to run them without restarting a repl really stinks.
Cursive’s protocol is similar to pREPL, but it’s structured in both directions, not just on returns.
Yeah, I can see that. I guess one potential middle ground would be to use a single background thread for evals which could be cancelled. That would maintain the sequential nature, but would still require bindings to be maintained etc.
otoh, now that you say that, I could just take care to always kick those off in a
Right, you could always do it manually yourself, which is a bit fiddly but possible.
But I also really like that middle ground that you mention, if you ever get around to it. No complicated session mgmt business. Just a dedicated solo thread pool.
In the meantime I’ll try out being vigilant with my infinite loops. If I fail catastrophically, I’ll be sure to let you know 😉
Here’s what the prepl server looks like BTW: https://github.com/clojure/clojure/blob/b1b88dd25373a86e41310a525a21b497799dbbf2/src/clj/clojure/core/server.clj#L191. It uses m/with-bindings: https://github.com/clojure/clojure/blob/b1b88dd25373a86e41310a525a21b497799dbbf2/src/clj/clojure/main.clj#L77
But as you can see, there’s really no thread management required at all, which keeps it really nice and simple.
Compare with this at your leisure :): https://github.com/nrepl/nrepl/blob/8223894f6c46a2afd71398517d9b8fe91cdf715d/src/clojure/nrepl/middleware/interruptible_eval.clj#L56
Haha, I have to go there pretty regularly. Anyway, the answer is: it’s possible, but I’m not sure it’s desirable. I’d have to try a PoC and see how it ends up.
Yeah, well. Consider it un-asked until I get back to you. I don’t think it’s crazy to pre-wrap in a future and self-manage.
Hehe, totally fair enough. Let me know if manually wrapping either doesn’t work or is unreasonably painful. You could potentially use REPL commands to make it easier.
@U07S8JGF7 afaik, nREPL uses
Thread#stop which has long been deprecated
I have a similar problem with the nREPL server of babashka. I can't use
Thread#stop there because it's not supported anymore in the GraalVM JDK
AFAIK the biggest problem with stop is that it doesn’t release monitors — which aren’t really an issue in clojure.
There’s no way to kill that (or in general, any uncooperative REPL process) except
BTW the problem is not actually that monitors are not released, it’s quite the opposite: > Stopping a thread causes it to unlock all the monitors that it has locked. (The monitors are unlocked as the ThreadDeath exception propagates up the stack.) If any of the objects previously protected by these monitors were in an inconsistent state, other threads may now view these objects in an inconsistent state. Such objects are said to be damaged. When threads operate on damaged objects, arbitrary behavior can result. This behavior may be subtle and difficult to detect, or it may be pronounced. Unlike other unchecked exceptions, ThreadDeath kills threads silently; thus, the user has no warning that his program may be corrupted. The corruption can manifest itself at any time after the actual damage occurs, even hours or days in the future.
From here: https://docs.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html