clojure-dev

Issues: https://clojure.atlassian.net/browse/CLJ | Guide: https://insideclojure.org/2015/05/01/contributing-clojure/
2020-02-24T03:49:41.003500Z

does anyone know what the 0[0-9]+ portion of the intPat regex in LispReader.java is supposed to handle? this is right before the (N)? at the end. https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/LispReader.java#L71 i am working on tree-sitter grammars for clojure and trying to understand these types of things in detail.

alexmiller 2020-02-24T03:52:55.003800Z

octal?

alexmiller 2020-02-24T03:53:10.004Z

guess not with 0-9

alexmiller 2020-02-24T03:53:49.004400Z

I guess it's just bigints with N suffix

alexmiller 2020-02-24T03:54:10.004900Z

?

seancorfield 2020-02-24T03:54:11.005Z

The octal bit is 0([0-7]+)

seancorfield 2020-02-24T03:58:32.006900Z

That's weird because it has a leading 0 and the N is optional. but 09N is a syntax error, and 010N is read as octal anyway. Maybe it's a way to parse all possible integer tokens and then the syntax error comes later when the parsed tokens are processed?

seancorfield 2020-02-24T03:59:58.008200Z

Yeah, looking at the stacktrace, I think the regex is used to determine "this is a number" and then the token is actually read and that's when illegal numbers are flagged...? LispReader line 352 throws the Invalid Number for 09 etc.

2020-02-24T04:56:57.013500Z

i read the alternation as among: 0, base 10 things with leading non-zero, hex, octal, num with radix, and mystery item the mystery item doesn't have its own capture group so may be it is for some kind of parsing as suggested (or some other purpose). iiuc, apart from the whole capture, there are only 8 capture groups and i only see the numbers 1 through 8 mentioned in matchNumber, so whatever the mystery item is for, it doesn't look like its value is directly reflected in any resulting number. thanks for the examination.

2020-02-24T11:43:21.014200Z

you could feed that regex to the test.chuck generator and see if it produces anything that doesn't match the same regex with the mystery portion removed

2020-02-24T12:29:19.014600Z

thanks for the idea!

2020-02-24T17:23:31.015400Z

With the mystery portion removed, it appears that the regex will no longer match a string like "09"

2020-02-24T17:42:38.016200Z

Maybe the mystery portion is there so "09" does match the integer pattern, because otherwise such a string would fail to match it, and then the reader would try to match it against the float pattern?

alexmiller 2020-02-24T17:43:17.016700Z

possibly something like that

2020-02-24T17:43:34.017100Z

And I think the float pattern would match "09", and such a string would be read as a floating point decimal 9.

2020-02-24T17:46:39.018Z

Yeah, quick test by modifying Clojure source code to get rid of the mystery pattern shows that (read-string "09") return a Double type 9.0, but Clojure 1.10.1 throws NumberFormatException

2020-02-24T17:49:15.019200Z

The current exception behavior for reading strings of digits with a leading 0, and at least one digit 8 or 9 in them, of throwing an exception, seems far preferable to returning a floating point number of the number read as decimal, given that all other strings of digits with a leading 0 are read as an octal integer.

seancorfield 2020-02-24T18:36:53.019800Z

@andy.fingerhut Thank you for taking the trouble/time/effort to actually verify what I suspected!

Janne Sauvala 2020-02-24T21:53:08.022700Z

Do you know if prepl is going to see more development in the near future? I noticed a few people got really exited when it landed in the Clojure code but I haven’t heard any official announcements about it

seancorfield 2020-02-24T22:05:39.023300Z

@janne What development is needed? It was designed to solve a specific problem, and it does that well.

Janne Sauvala 2020-02-25T08:16:55.082700Z

Thanks @seancorfield. That was my hunch it’s similar to the nREPL protocol (afaik). There was good discussion at the channel some of the current problems (that other repls also have)

seancorfield 2020-02-25T16:31:01.089500Z

It's not like nREPL in some really fundamental ways. It's still a pure streaming REPL like the console REPL and the socket REPL. But, yeah, it's designed for program to program communication such as tooling in the same space that nREPL exists.

1
seancorfield 2020-02-24T22:06:25.024Z

Various tooling developers are starting to use it -- it's kind of a niche feature that will really only appeal to tooling developers.

Janne Sauvala 2020-02-24T22:07:24.024500Z

Oh, could you elaborate what is the specific problem?

Janne Sauvala 2020-02-24T22:10:26.027200Z

I have only used nREPL and I know some (like you) like to use the socket REPL. I was thinking that prepl was missing some features because it’s not used by that many people

seancorfield 2020-02-24T22:16:08.027400Z

prepl is designed to be used by code, not people. It's designed for tooling.

seancorfield 2020-02-24T22:16:54.027600Z

It has no prompt. It returns a hash map of the result value, the output (if any), the error (if any) for each evaluation. Which is what a program wants when interacting with Clojure.

dominicm 2020-02-24T22:22:54.029100Z

Some tooling authors have had issues with it and would welcome work on things like interruptible evals, nesting, etc.

seancorfield 2020-02-24T22:27:15.029600Z

Yeah, I think the lack of interruptible evals is probably the thing that would concern me most as a tooling author.

ghadi 2020-02-24T22:41:45.030200Z

nREPL’s “interruptible eval” is totally busted

ghadi 2020-02-24T22:41:51.030500Z

Calls Thread/stop, which is deprecated for good reason

seancorfield 2020-02-24T22:45:13.031100Z

I wonder how @mauricio.szabo does it in Chlorine? I'll go and ask...

seancorfield 2020-02-24T22:48:24.031800Z

It relies on unrepl. When an evaluation is submitted, it is run in a future, and returns a function to call if you want to (try to) cancel the future.

ghadi 2020-02-24T22:49:06.032100Z

that makes more sense

seancorfield 2020-02-24T22:51:06.033300Z

@ghadi Do you think that is something that could be integrated into prepl? I get the impression prepl is purely synchronous at the moment, yes?

alexmiller 2020-02-24T22:51:41.034100Z

No plans to work on prepl at this moment, but that doesn’t really mean anything. Could be picked up at anytime

1
seancorfield 2020-02-24T22:52:33.035500Z

(there's also the issue of evaluation produces really large -- or even infinite results -- which I believe prepl just tries to return in full?)

seancorfield 2020-02-24T22:52:57.036200Z

I guess both of those are "hard" problems to solve on top of the current prepl architecture?

ghadi 2020-02-24T22:53:17.036600Z

@seancorfield not unless either 1) eval is parameterized or 2) the client always sends in a wrapper form for their eval form

ghadi 2020-02-24T22:54:22.037Z

(^ re: interruptibility, not re: printing)

favila 2020-02-24T23:03:27.037300Z

What’s the alternative?

ghadi 2020-02-24T23:03:58.037500Z

abandon the computation

👍 1
ghadi 2020-02-24T23:04:05.037700Z

or check Thread/interrupt status

favila 2020-02-24T23:04:31.037900Z

how could it do that with arbitrary code?

ghadi 2020-02-24T23:04:39.038100Z

you don't

2020-02-24T23:04:51.038300Z

Out of curiosity, what does "abandon a computation" mean that is different than calling some Thread stop/cancel/whatever operation?

ghadi 2020-02-24T23:04:52.038500Z

Thread/interrupt requires cooperation from the evaluated code

favila 2020-02-24T23:05:19.038700Z

I agree that it’s busted, but the only safe option is cooperative multithreading which requires the running code to buy-in (at least checking interrupt status or yielding)

ghadi 2020-02-24T23:05:30.038900Z

abandon means just don't wait on the result of the code

favila 2020-02-24T23:05:49.039100Z

thread/stop at least stops the cpu from spinning forever

ghadi 2020-02-24T23:05:55.039300Z

it's busted in conception, not implementation

ghadi 2020-02-24T23:06:03.039500Z

but it's also busted in implementation

ghadi 2020-02-24T23:06:20.039700Z

please read the doc of Thread.stop

favila 2020-02-24T23:06:36.039900Z

I understand why thread.stop is bad

favila 2020-02-24T23:08:32.040100Z

I would also be sad if nrepl didn’t use it 🙂

👍 2
2020-02-24T23:08:34.040300Z

It seems to me maybe roughly the same amount busted as "kill -9" on a Unix process that is one of potentially many cooperating processes? I understand those aren't identical, but seems they could have similar coupling issues that affect things in a similar way, e.g. JVM object locks <-> Unix file system locks.

favila 2020-02-24T23:09:32.040600Z

the surface area of object monitors seems to me much bigger than unix file system locks

favila 2020-02-24T23:09:53.040900Z

you can always clear a file system lock problem

ghadi 2020-02-24T23:09:59.041100Z

yeah

favila 2020-02-24T23:10:11.041300Z

but a jvm with thread monitors in a busted state is just broken and leaking/deadlock prone forever

favila 2020-02-24T23:10:28.041500Z

and every object is suspect that that thread ever referenced

2020-02-24T23:12:58.041700Z

You can delete the lock file, but problems of system invariants being violated can persist past deleting it, just as for object locks. Agreed if surface area here means JVM object locks are used far more often than Unix lock files, but not sure I see a fundamental difference between the kinds of problems that result.

ghadi 2020-02-24T23:15:29.042Z

breaking core.async channels is a big risk too

ghadi 2020-02-24T23:15:46.042200Z

how do you stop (deref (promise)) ?

ghadi 2020-02-24T23:18:03.042800Z

oof even unrepl calls .stop on the thread

2020-02-24T23:19:43.043300Z

there isn't anything else

2020-02-24T23:20:16.043900Z

there is no other mechanism to stop a thread doing arbitrary things

ghadi 2020-02-24T23:21:18.045Z

there is abandoning the eval, or calling Thread/interrupt (which requires cooperation)

2020-02-24T23:21:26.045300Z

right

2020-02-24T23:22:01.046200Z

for eval, which is the most general of computations, there is no way to interrupt it other than calling thread.stop, as deprecated as that is

2020-02-24T23:24:00.046500Z

Maybe Thread.stop() is as useful/expedient in development situations, and has many possible sharp edges, just as def of a function in a running REPL is?

2020-02-24T23:24:55.046700Z

We don't think twice if we do it, because we know how to handle our chef's knives without cutting ourselves, but we are always worried others will be cutting themselves?

2020-02-24T23:27:56.047600Z

I said this in a thread earlier, but repeating here in case it is useful to anyone. I don't claim it is deep or anything: Maybe Thread.stop() is as useful/expedient in development situations, and has many possible sharp edges, just as def of a function in a running REPL is? We don't think twice if we do it, because we know how to handle our chef's knives without cutting ourselves, but we are always worried others will be cutting themselves?

alexmiller 2020-02-24T23:30:13.048100Z

The plan is to actually remove it in the jvm soon

jumar 2020-02-25T11:40:23.084900Z

That's interesting. I couldn't quickly find any details about that. The only thing I've found is the removal of destroy and stop(Throwable) [http://mail.openjdk.java.net/pipermail/jdk-dev/2018-June/001362.html] which also mentions: > > Note that the no-arg Thread.stop() method still works and won't be removed by > this changeset. It remains deprecated (though not for removal) and there are no > plans to remove it at this time.

2020-02-24T23:30:48.049Z

Wow. For the JVM, that is really saying something.

alexmiller 2020-02-24T23:30:57.049400Z

I think people don’t realize how dangerous it is

ghadi 2020-02-24T23:31:25.049700Z

^^

ghadi 2020-02-24T23:32:32.051Z

if you have a runaway computation initiated through the REPL, who cares? if you stop a Thread and your whole app breaks, that is worse IMHO

ghadi 2020-02-24T23:33:31.052200Z

I can't count how many times have I hit Ctrl-C Ctrl-B (interrupt) in Emacs and everything breaks

alexmiller 2020-02-24T23:36:30.053800Z

Actually they did already remove destroy() and one of the stop() methods in Java 11

2020-02-24T23:37:41.054100Z

I sure hope they leave kill -9 in Unix 🙂

jumar 2020-02-25T11:41:32.085100Z

Which still doesn't mean you can always kill a process this way (hint: uninterruptible sleep).

2020-02-24T23:43:39.054300Z

thanks for the investigation (and the previous tips for compiling clojure from source). i also built a modified clojure and was able to see for myself :thumbsup:

ghadi 2020-02-24T23:44:37.054600Z

ghadi 2020-02-24T23:44:48.055100Z

Thread interrupts work fine for a large amount of usecases

ghadi 2020-02-24T23:45:12.055700Z

but not something like infinite seqs (reduce + 0 (range))

ghadi 2020-02-24T23:46:00.056800Z

(although if you tried to print an infinite seq, you could handle that through an interrupt)

2020-02-24T23:46:43.057700Z

good to know. So without Thread.stop, a thread that doesn't respond to Thread.interrupt(), and hasn't been written to poll some state asking it to quit, is only stoppable via killing the entire JVM process?

ghadi 2020-02-24T23:47:19.058300Z

I think that's right

2020-02-24T23:47:45.058400Z

no problem. You made me curious what was going on, and thankfully it didn't take long to find out.

🙂 1
ghadi 2020-02-24T23:49:16.060Z

I'm more interested in: how can I give input control back to the initiating REPL? how can I surface a long computation? than stopping the long computation

2020-02-26T00:38:54.093200Z

regarding input control back, i use additional socket repl connections. i guess that's not the initial repl -- what are the benefits in it being the initial repl over a new one?

ghadi 2020-02-24T23:49:55.060500Z

the answer is to trick out your eval function

ghadi 2020-02-24T23:50:07.060900Z

wrap clojure.core/eval

2020-02-24T23:57:09.063200Z

so you are saying, when you accidentally evaluate code that is copying the same data to a new file over and over again in infinite loop, you are more interested in "surfacing" and making that computation "visible", not stopping it?

ghadi 2020-02-24T23:59:38.065Z

"stopping" it

2020-02-24T23:59:48.065300Z

like, I think it is one thing to explain and understand why Thread.stop is a problem, but is kind of nuts to tell people they are wrong for wanting to stop bad loops running while doing iterative developement in a repl