Fork me on GitHub
#clojure
<
2023-06-27
>
markx02:06:55

Question about Java interop: is it possible to extend an abstract class and then call its static method? E.g. Is it possible to call this launch method? https://github.com/AlmasB/FXGL/blob/22c7ecf98ac2420afac8bd00b8cbed21f09b6f27/fxgl/src/main/java/com/almasb/fxgl/app/GameApplication.java#L49-L52

p-himik07:06:10

(GameApplication/launch args) should work just fine.

markx04:06:37

It doesn't work. I gave up on this lib. πŸ˜•

p-himik07:06:55

What does "doesn't work" mean? Does it throw? Does something misbehave?

Alexander Kouznetsov18:06:11

Apparently something is not working around this line var appClass = ReflectionUtils.getCallingClass(GameApplication.class, "launch");?

Alexander Kouznetsov18:06:50

That might be really expecting java stack trace and not clojure one. So you might want to have a slim java wrapper around it to make it work with clojure. https://github.com/AlmasB/FXGL/blob/dev/fxgl-core/src/main/java/com/almasb/fxgl/core/reflect/ReflectionUtils.java#L230

2
roklenarcic16:06:23

If I want to emit edn that’s nicely formatted, not just all in one line, how would I do that?

p-himik16:06:53

zprint would be another, if you require something that pprint doesn't offer.

βž• 2
vemv17:06:42

https://github.com/brandonbloom/fipp would a nice production-oriented choice. Code formatters might be designed for a different set of constraints.

πŸ‘ 2
pesterhazy18:06:22

on the command line there's https://github.com/borkdude/jet, which I believe pretty-prints by default

isak19:06:03

I like to use https://github.com/greglook/puget on the command line if colors make sense

πŸ‘ 2
roklenarcic20:06:45

Thanks everybody

nuriaion17:06:02

Hi i'm currently learning clojure and how you debug your programs? Is it possible to set a breakpoint and get a repl there? (I'm using neovim conjure and clojure lsp)

p-himik17:06:54

I use Cursive and debugging there is pretty much first-class, with breakpoints and whatnot. So it's at least possible in principle. Although not sure about having a REPL at a breakpoint. However, FWIW I rarely use it. Instead, I usually use tap> along with Portal and, if some piece of code is relatively self-contained, incremental evaluation via REPL (i.e. I send different pieces into REPL and check whether the output corresponds with my expectations).

πŸ‘ 2
Olav Fosse17:06:44

REPL at breakpoint works great in CIDER at least :^): https://docs.cider.mx/cider/debugging/debugger.html

πŸ’― 4
nuriaion18:06:06

ah nice. I didn't knew about tap> and Portal

p-himik18:06:09

There are lots of other tools. Reveal, and a recently released Morse. If you like debuggers, you might find FlowStorm an amazing tool since it allows you to time travel, among other things (here's https://www.youtube.com/watch?v=YnpQMrkj4v8). There are definitely other things - these are just the ones I could remember at the moment.

didibus18:06:03

Cider (emacs) and Calva (VSCode) both have one as well.

didibus18:06:29

I don't know if conjure has it, I'd think not

enn18:06:42

I’ll put in a plug for https://github.com/vvvvalvalval/scope-capture. It lets you capture the local bindings at any given code site (kind of like a breakpoint, but without actually stopping execution). Then you can interact with them in the REPL.

nuriaion18:06:29

That's a lot of interesting options!. Thanks a lot!

jesse18:06:33

cursive's debugger is a traditional line-oriented debugger, allowing stepping out of uninstrumented clojure functions, as well as into and out of Java methods. I'm curious to know if Calva (and other tools mentioned here) support those operations? I just haven't looked.

jpmonettas18:06:41

hi @U0BQ9CF8T, I have been working in #flow-storm for quite some time which is a debugger that works for Clojure and ClojureScript and is IDE independent. Here I leave you a 10min video of some of the most important features https://www.youtube.com/watch?v=Mmr1nO6uMzc, which is newer than the video linked by @U2FRKM4TW before to give you a sense of how it can help you

πŸ‘ 2
didibus18:06:38

@U05DWENKHSS The ones based on nRepl cider debugger do support that. But they only support it for Clojure code, so they won't step into/out of Java interop.

jesse18:06:37

@U0K064KQV for a case like the following, if I instrumented ex-2 and stepped until that function returned, I would exit the debugger, unless ex-1 were also instrumented, right? I hope I didn't miss a big thing πŸ™‚

(defn ex-2 [x]
  (+ x 1))

(defn ex-1 [x]
  (let [x (ex-2 x)]
    (+ x 1)))

(t/deftest example
  (t/is (= 3 (ex-1 1))))

jesse18:06:11

(mainly curious: If I could do those two debugging things, I'd be able to get along without cursive)

didibus18:06:29

Hum, pretty sure it wouldn't exit

didibus18:06:54

Let me try it 2sec

didibus18:06:15

Hum, I was wrong, right I see, if you instrument ex-2, yes it will exit. You need to instrument the entry point. So if you instrument ex-1, when you step into ex-2 it will continue into ex-2 and step through ex-2

jesse19:06:15

Thanks, I appreciate your verifying. It's sometimes been useful with cursive to explore beyond the entry point -- I realize that's a specific tactic, and that you could always look at the stack and choose earlier entry points.

didibus19:06:49

Ya, Cursive is the champ I would say for debugging. But Cider's is easier to get in/out of, because it's repl based.

jesse19:06:40

Both have advantages: I can't think of anything that one or the other didn't shed light on.

jpmonettas19:06:57

one disadvantage of the Cursive debugger (I think a big one) is that is not expression based, just line based, so it is "ok" for looking at the flow, but not good at looking at all the intermediate values, which I think is much more useful in Clojure. Same issue that the browser debugger has for ClojureScript

didibus19:06:06

What exactly do you mean by looking at intermediate values? I'm not sure I follow the difference

jpmonettas19:06:53

@U0K064KQV here I just made a small video with what I mean

jpmonettas19:06:51

so, unless I'm missing something I don't get a lot of value from stepping over in Cursive, I just get to see that the local n has the value 70

jpmonettas19:06:25

the only pro I see for the Cursive debugger (comparing to FlowStorm and cider-nrepl ones) is in its ability to step also over Java code, if you normally do that

didibus20:06:32

Hum, right like it doesn't show the intermediate values as it goes through the sequence pipeline? I'd have to try that in cider to see what it does.

practicalli-johnny20:06:21

As specific expressions can be evaluated in the REPL the need for a step debugger is far less in Clojure than with other (non-lisp) languages. I tend to pull apart any complex code and evaluate its parts to help me understand what it's doing. I rarely use a debugger except perhaps for convoluted loop recur code (which tends to be refactored anyway) Portal with Neovim Conjure are sufficient for the majority of cases (there is also a DAP feature planned for Conjure to provide debugging) https://practical.li/clojure/data-inspector/portal/

didibus20:06:55

@U0739PUFQ I do need to try flowstorm again, the UX looks great. I think it's the added setup for it as compared to the cider debugger that's just there haha

jpmonettas20:06:42

@U0K064KQV it doesn't require much setup, just an alias that you copy and paste into your deps.edn or project.clj. Since ClojureStorm, for the most, you don't need to think about instrumentation either. So I would say you get to record everything your program is doing for free.

jpmonettas20:06:09

> As specific expressions can be evaluated in the REPL the need for a step debugger is far less in Clojure than with other (non-lisp) languages. I don't fully agree with it. I think it is super powerful to be able to call our functions from our editors, but for systems where functions inputs are complicated values, it is impractical to type the function calls inputs, so you need to rely on some kind of scope capturing, which is also not easy to do for different reasons, like capturing a function inputs when it is being called many times, etc. Also I think that because they are called debuggers a lot of people think about them only in the presence of bugs, which I find to be a small subset of their use. I mostly use them to understand by seeing, which is specially important in dynamic typed languages were you otherwise need to only rely on names and doc strings.

πŸ’― 2
jpmonettas21:06:54

> I'd have to try that in cider to see what it does. @U0K064KQV Stepping wise, Cider will step like FlowStorm and show all intermediate values, the difference being that you can only step forward, and you need to explicitly instrument/un-instrument what you are interested in, while in FlowStorm you can jump around in time as you need.

πŸ‘ 2
didibus21:06:29

Ya, I too think people devalue the usefulness of debuggers, I see people saying they use tap> or println, or even people add tracing libs and all that. Yes you can get away with just doing that, and sometimes I do that when I need to see a single value or something easy, but debugging with cider (or it looks like with FlowStorm), is super fast and you'll debug things way faster than manually adding some taps and removing them for example.

igrishaev12:06:07

there is a bogus library that does exactly what you want: it interrupts execution and shows a graphical window with REPL and local vars. It also doesn't depend on any kind of editor

igrishaev12:06:01

and more: it's free from JavaFx, and any kind of deps in general

igrishaev12:06:39

sometimes, I spent hours hanging in it, querying the database in the middle of transaction, drinking tea

jpmonettas12:06:25

for people that don't like JavaFx or external windows want to mention that #C03KZ3XT0CF doesn't depend on it, if you are using Emacs there is cider-strom, which uses FlowStorm from an Emacs UI

jpmonettas12:06:39

looks like this

didibus22:06:07

Oh! Now I can get onboard

mtbkapp20:06:48

I found something interesting with EDN. Is there a way to specify a keyword with a space in it? It turns out that it is possible to encode one but not decode one in Clojure. Example:

(require '[clojure.edn :as edn])
nil
(def edn-string (prn-str {:color (keyword "Dark Blue")}))
#'user/edn-string
edn-string
"{:color :Dark Blue}\n"
(edn/read-string edn-string)
Execution error at user/eval7 (REPL:1).
Map literal must contain an even number of forms
user=> 

p-himik20:06:40

A known case. Spaces are not valid but keyword fn won't complain.

dpsutton20:06:54

no way to read such a keyword with the clojure or edn readers

mtbkapp20:06:43

Thanks for the responses. I've got some data already written with this so I'll have to come up with a way to read it.

didibus20:06:09

I think I did add support for that in one of my code base once. Can you have a custom reader for keyword? Maybe it's possible to set one. Or it's possible what I had done is print those keywords with a custom literal and read them back.

didibus20:06:58

(clojure.edn/read-str {:readers {'keyword custom-rdr}} ...) Not sure if something like that works

Jake Pearson20:06:59

That's a neat idea.

dpsutton20:06:47

my gut reaction would be to leave strings as strings

βž• 2
mkvlr20:06:08

not possible to read it in edn but in Clojure you can use #=(keyword "foo bar")

Jake Pearson20:06:08

I've never used #= what does it mean?

pppaul21:06:14

you can also make a keyword from the empty string, those ones are very cool looking.

mtbkapp21:06:56

Oh my. Well I guess I'd be in the camp that the clojure.core/keyword should probably do some validation. Oh well. Thanks for the discussion.

didibus22:06:56

Ya, I think it's a performance and backward compatibility thing. Code uses it now where it didn't validate, and if you added validation it would break a lot of things. Also, performance I think, overhead of validation basically.

mtbkapp22:06:24

That makes sense.

pppaul22:06:27

i have code that does make keywords with the empty string, it's useful in web encoding/decoding. though the empty keyword is not very useful except to be checked and to throw an error or turn it into nil