Fork me on GitHub
#clojure
<
2022-05-18
>
Alys Brooks04:05:04

Is there shorter way of creating a hash-map from a collection and function, where the original elements become the keys and the result of apply the function to the elements becomes the values. I plan to do it with (zipmap coll (map f coll)) , which to be fair, is pretty concise.

dpsutton04:05:58

that's about as short and concise as it gets

jumar05:05:44

Here's another option but it's even longer:

(into {} (for [x coll] [x (f x)]))

mpenet06:05:33

(into {} (map (juxt identity f)) xs) for the sake of using juxt

Alys Brooks07:05:16

Thanks! I guess I was wondering if there was a clojure.core function that does what I wanted that I overlooked.

jumar08:05:38

I guess that's way too specific to be included in the core. It reminds me a bit medley.core/index-by (or more general group-by) but here it's reversed - mapping from item to (f item) rather than mapping from (f item) to item

jumar08:05:09

So this would be a complicated way to do it too 🙂

(->> [1 2 3]
     (medley.core/index-by str)
     (clojure.set/map-invert))
;; => {1 "1", 2 "2", 3 "3"}

pinkfrog09:05:01

How do you use queue in clojure, the clojure.lang.PersistentQueue one or else?

p-himik09:05:54

(conj clojure.lang.PersistentQueue/EMPTY some-item). Just like any other immutable collection in Clojure, with the only difference being the way you create an empty queue. Other common operations would be peek and pop.

jumar10:05:47

If you use medley there's medley.core/queue which does the same thing

pinkfrog11:05:48

Good to hear.

pinkfrog11:05:05

Looking at the medley lib, seems not many killer functions. Maybe only the deep-merge count as one http://weavejester.github.io/medley/medley.core.html#var-deep-merge

jumar16:05:57

I used to use map-vals before Clojure 1.11. Index-by is useful too, and assoc-some. It's a minimalistic library but imho quite useful

Yogesvara Das09:05:25

Is there good native solutions if I need TLS? The stuff I'm finding on github is quite old.

Linus Ericsson09:05:21

I don't know exactly in what sense you ask, but sometimes we use https://github.com/aphyr/less-awful-ssl and sometimes we try to use p12-keystores instead of the JKS ones.

pieterbreed11:05:47

Hi everyone; I have a weird mismatch in behaviour between REPL and uberjar. For (println (java-time/instant)) in REPL I get #inst "2022-05-18T11:24:01.699124574-00:00" and with uberjar I get #object[java.time.Instant 0x70cd122 2022-05-18T11:25:40.441559477Z]. Has anybody encountered this and is there some magic I'm unaware of?

vemv11:05:57

I think it was cider-nrepl?

pieterbreed11:05:15

this is blowing my brain a little bit... let me check...

delaguardo11:05:56

cider adds some print-method implementations but not for java.time.Instant

pieterbreed11:05:32

Indeed, I think @U45T93RA6 is correct; with lein repl when I print an instant I get the #object format

delaguardo11:05:52

for me it prints #object[java.time.Instant with cider-nrepl

pieterbreed11:05:06

As a follow-up question; How can I enable the #inst format for java.time.Instant? It seems like https://clojure.atlassian.net/browse/CLJ-2224 is/was an attempt to add it, but the issue is still open, so I'm guessing it did not get merged yet.

delaguardo11:05:26

you can get method implementation using (get-method print-method java.time.Instant)

delaguardo11:05:24

if something adds an implementation then you will see it in the namespace. (it should be different from clojure.core/...)

pieterbreed11:05:46

(get-method print-method java.time.Instant)
#function[cljs.instant/fn--727]

delaguardo11:05:24

which is enabled in dev but disabled in uberjar (and that is fine i think)

delaguardo11:05:56

to answer your follow up question - just copy the patch from the issue somwhere in your code base 🙂

👍 1
🙂 1
pez15:05:56

I notice that I have a gap in my understanding of how a Clojure program springs into existence. Trying to introduce what the REPL is, and brings to the table I wrote this: > Inside Clojure runs the REPL. To understand this REPL, let's start with what happens when a Clojure program is created. It is done in these steps: > 1. The Clojure Reader, reads the source code of some first file > 2. The text is converted to Clojure data (Clojure code is data) > 3. This Clojure data is sent to the Clojure Compiler, which compiles it to Java byte code > 4. This compiled code is then evaluated. And if this first file requires other files, this process is repeated for them as well. Including this step. > > Step 1 is Reading. Step 1-3 happens at compile time. Step 4 is Evaluating. Evaluation happens at run time. Once all of a Clojure program is compiled, and the program is running, only evaluation of compiled code is going on. > > However, during development the services like the Clojure Reader and Compiler are still there. And they can read new code and replace any part of the compiled program, while it is running. This makes the Clojure REPL something different than what you might think of as a REPL, such as the one in Python or the console in JavaScript. > > The R in Reading and E in evaluation are the RE of REPL. The REPL is the program that uses the Reader and the compiler and the evaluator, then ”Prints” the results (that is sends it back to the user) and Loops back ready to Read new code. > > That you can compile, and install new or updated parts of your programs is what opens up for what we refer to as Interactive Programming, or sometimes REPL Driven Development. > ... To me it looks a bit funny there with step 4, a circular reference, or a snake eating up itself from the tail... Any help with getting this right would be super appreciated! (Not just step 4, I am very good at misunderstanding things in general.)

Ben Sless15:05:50

There's a bit you missed where: Clojure's runtime is initialized The core namespace is loaded first which bootstraps the language, runtime and reader This is stage 0, so to speak, then you don't have the snake eating its tail

pez15:05:04

Thanks! So I added: > 0. Clojure's Core namespace is loaded, which bootstraps the language, the runtime and the Reader Is the rest largely correct, you mean?

Ben Sless15:05:48

First the Runtime class is initialized, then core is loaded, it populates some vars used by LispReader then you're off to the races

Ben Sless15:05:25

The rest seems accurate to me, there's also a good talk about this somewhere about Clojure's compiler

pez15:05:20

This is supposed to be entry level stuff. 😃 But I'll add the things you mention anyway, because cognitive dissonance hurts.

Alex Miller (Clojure team)15:05:30

I don't understand step 1, I thought you were talking about the REPL

Alex Miller (Clojure team)15:05:19

if you're talking about a repl, it's not reading any files, it's waiting to read something from the terminal

Alex Miller (Clojure team)15:05:20

there are multiple other ways to "run" a Clojure program with some subtle differences (but I wouldn't call these the REPL)

pez15:05:30

I'm going to show Calva's Getting Started REPL thingy. So I want to let the viewers know what has happened up to that point when we start REPL-ing. No terminal involved.

Alex Miller (Clojure team)15:05:56

but, there isn't a file being read is there?

pez15:05:35

The Getting Started REPL starts with loading a file.

Alex Miller (Clojure team)15:05:03

(sorry, I'm catching up on the docs)

Alex Miller (Clojure team)15:05:18

I guess I'm curious what that actually does - clearly you open these files in Calva, and you start a repl. do you actually load one or all of them?

pez15:05:20

The text above continues: > So here all of the above has happened. Calva has started a Clojure REPL and also evaluated this file. That means that all these vars defined in this namespace are created. And you can see that the file is evaluated by the fact that this ”Welcome” text is printed. It is the last thing in this file.

pez15:05:56

You are identifying a weak spot in the getting started REPL, @alexmiller...

pez16:05:41

Calva makes a promise never to evaluate anything you don't ask it to evaluate. But the getting started REPL actually evaluates this first file. Not the other two though.

pez16:05:50

I tried without loading it first, but it didn't quite have the right "This Guide has started” effect.

Alex Miller (Clojure team)16:05:18

ok, that catches me up :) so I think there is a difference in describing what has happened vs "what happens when a Clojure program is created". it's different for a good reason, but maybe it should not mislead you into thinking this is normal?

pez16:05:35

However. It is the REPL doing it. So it is a bit of a lie that ”all the above” has happened, maybe. But I think it is fine. I just want to set the stage for appreciating what the REPL is, and how it might not be what you think it is.

Alex Miller (Clojure team)16:05:32

I would combine 1. and 2. - the Clojure Reader is importantly the component that reads the text and makes Clojure data.

🙏 1
Alex Miller (Clojure team)16:05:52

I don't know if you want to get into this, but it is an important difference from other languages (like Java) that "read" is not "read a file" but "read the next form" and compilation happens on a per-expression basis

Alex Miller (Clojure team)16:05:16

and this is NOT DIFFERENT than you typing it into the repl yourself

pez16:05:46

The text actually continues in this direction. 😃 > Calva is a REPL client hooking the files you edit to the REPL running inside that compiled and running app. We can send things to this REPL by selecting it and run a command. > > You don't need to select things, though, Calva is pretty good at sending the right thing to the REPL. There's a video about it on this channel ”The Current Form”. You use ctrl+enter to evaluate the current form. The reason Calva can do this is that Clojure is a LISP and the code is structured in nested list. Then I have no more text, because I stopped and thought that maybe i had gotten the mechanisms wrong there.

Alex Miller (Clojure team)16:05:19

in some sense, I think it is actually backwards to start from the REPL (or talk about the REPL at all), the important bit is that doing anything in Clojure follows the process of reading Clojure code (a string) into Clojure data, (which is compiled to bytecode and loaded into the JVM but maybe you can avoid talking about this for a long time), then evaluates the Clojure data

Alex Miller (Clojure team)16:05:49

where does text come from? read from a file, open in your editor, or hey you can also just type it into a terminal

pez16:05:15

Good points! I'll have a think. There is some constraint here in that the feature is called Getting Started REPL. And I feel a need to elaborate a bit on what do I mean by a REPL, since it carries many connotations.

Alex Miller (Clojure team)16:05:17

the last time Rich and I talked about this in depth, we talked about how we should talk less about the REPL and more about interactive development. much better to focus on interactive "eval from my code"

📣 1
Alex Miller (Clojure team)16:05:45

yeah, I'm giving you big picture ideas here, I'll let you figure out how to express :)

pez16:05:13

I'm in that camp too, actually. I say Interactive Programming in the text above, Should I use Interactive Development, you think?

Alex Miller (Clojure team)16:05:28

teaching people to type things in a REPL is a dead end. teaching them to interactively develop in their source is alien superpowers

👍 1
Alex Miller (Clojure team)16:05:59

either of those is fine, the "interactive" (vs REPL) is the important bit

pez16:05:01

That's the mission I am on. 😃

pez16:05:10

That's why no terminal. But I intend to show that you can also send stuff to the REPL from the prompt. To have the prompt and the file open side by side opens up for some comparisons that can drive this point home, I think.

Alex Miller (Clojure team)16:05:54

isn't there some other tool that has no prompt at all? I think that is a bold but maybe interesting choice.

pez16:05:26

Though I do have a dead end in the Getting Started REPL thing still. There is no project created that the user can continue with. I intend to fix that.

Alex Miller (Clojure team)16:05:48

yes, that's an important connector

pez16:05:05

Clover doesn't have a prompt. I think that was some MVP think at first, but people liked the bold move and it never got a prompt. 😃 Maybe I am not having this entirely correct. @U3Y18N0UC should tell the story, not I.

Alex Miller (Clojure team)16:05:38

personally, I think it is mis-step to talk about stuff like project templates and clj-new etc at the point of moving to a project - really you need almost nothing to be in a project (a deps.edn with {} and a src/ dir)

pez16:05:48

Yes. I have many such projects. 😃 Calva has a few ClojureScript starter commands that create this as well.

Alex Miller (Clojure team)16:05:04

anyways, I appreciate you working on this and am happy to provide feedback (if you want it, I know you have plenty of your own ideas and I'm not trying to tell you what to do :)

pez16:05:48

I live by the mantra ”Don't tell me what to do!”, so it wouldn't do you any good if you did anyway. 😃 Appreciate the feedback a lot!

1
seancorfield17:05:20

You can get away with no deps.edn file too and just have src/ and some code (until you need dependencies) but I don't know whether that's helpful or not in this case...

mauricio.szabo17:05:51

@U0ETXRFEW About Chlorine/Clover, the full story is less beautiful 😄. To iterate faster, I used an UI library on Atom that did have the prompt, but I simply ignored it because it would take more time to have the first version ready. People got confused with the prompt that did nothing, so I removed it via CSS :rolling_on_the_floor_laughing:

😂 1
mauricio.szabo17:05:42

Then that UI library changed (like, A LOT) and I quickly wrote a version of the console tab by myself, I believe in a couple of hours, to at least keep Chlorine working. Obviously, missing the prompt again...

seancorfield17:05:00

I guess I didn't realize that Calva's output window is actually a REPL you can type into as well, since I came from Clover where there was no "typing into a REPL"... 🙂

seancorfield17:05:37

(why would anyone type directly into the REPL? that's crazy talk! :rolling_on_the_floor_laughing: )

😂 1
mauricio.szabo17:05:30

Finally, I was happy with Shadow-CLJS (ClojureScript) support and decided to re-visit the idea of being able to type on the REPL. By that point, almost all of the code was depending on a text editor being selected. Well, if you have the console selected, the editor does not really know which TextEditor it needs to use, so in the end.... I left as that. @U04V70XH6 with his preaching of "never type in the REPL" helped me a lot to both understand that I made the right decision (even if by accident 😄), and to convince people that "it is not a bug, it is a feature!" (spoiler alert, it was a bug but ended up becoming a feature :rolling_on_the_floor_laughing: )

Carsten Behring20:05:07

Using https://github.com/nextjournal/clerk and https://github.com/scicloj/clay results in even less reasons to even look into the REPL at all, the browser becomes the (read-only and graphical) P of the REPL

seancorfield20:05:47

@U7CAHM72M I use Portal, inside VS Code, so everything is part of my (full-screen) editor context and I don't need to switch to a browser for anything.

radu21:05:20

@alexmiller Tonsky's Clojure Sublimed has no prompt and doesn't need any other files; if deps.edn is in the $PWD it will use it, but works fine without.

radu21:05:26

It needs a nrepl server to connect to, so I guess that if nrepl server is started with -i (interactive) option it can have a prompt.

pieterbreed16:05:28

Do I have to do something special to make clojure.data.json/write-str write java.time.Instant without throwing an error? It seems as if there is support for it via JSONWriter protocol, yet I get:

(require '[clojure.data.json :s json])
 (json/write-str (java.time.Instant/now))

Execution error at clojure.data.json/write-generic (json.clj:385).
Don't know how to write JSON of class java.time.Instant
My classpath (only) contains [org.clojure/data.json "2.4.0"]

hiredman16:05:16

are you sure?

hiredman16:05:40

that line number doesn't match that function in version 2.4.0

Alex Miller (Clojure team)16:05:40

Any chance you have Clojurescript on the classpath?

pieterbreed16:05:03

ok... I think I get the message... this is the second time today I'm struggling with java.time.Intstant, and both times it was having cljs in the classpath. I guess I never realized I shouldn't do that. Thanks for input :thumbsup:

Alex Miller (Clojure team)16:05:33

Clojurescript includes an older version of data.json in it

Alex Miller (Clojure team)16:05:52

That problem is fixed in the new version of ClojureScript!

🎉 2
Alex Miller (Clojure team)16:05:13

It's not your fault and this should not be an issue :)

pieterbreed16:05:12

oh wow... this validation feels so good when I've been banging my head against it for a while. I will update. Thanks again

😎 1
wilkerlucio20:05:18

hello folks, does anyone know if there is a tool to navigate on EDN data on terminal? I'm looking for something that allows to navigate some generic EDN structure, able to expand/collapse parts as we go

p-himik20:05:16

> able to expand/collapse parts as we go How would it work in a terminal?

phronmophobic20:05:00

In principle, it wouldn't be that hard to add terminal support to https://github.com/phronmophobic/viscous, but I'm not sure what benefit there is to having a TUI when you can have a GUI. Are you trying to inspect data over the network via ssh?

phronmophobic20:05:43

> How would it work in a terminal? It's not used very often, but most terminals have mouse support.

mdave20:05:17

https://github.com/borkdude/jet might be a good fit. I usually use it from inside vim which makes it easier to explore the data.

wilkerlucio22:05:41

@U2FRKM4TW I imagine like on Emacs you can expand/collapse sections (think Org Mode)

wilkerlucio22:05:04

@U7RJTCH6J no network, I just wanted a simple way to view, I'll check viscous, seems to be what I'm looking for 🙂

phronmophobic22:05:13

Ah ok. You may also want to check out https://github.com/djblue/portalwhich is a bit more polished. If you're using emacs, you can also try M-x cider-inspect

wilkerlucio23:05:07

I do use portal all the time in dev 🙂, this is more for a case where I have no REPL

👍 1
phronmophobic23:05:12

Sounds good. Viscous does let you just pass a file or read stdio. Feedback is welcome!

wilkerlucio23:05:50

@U7RJTCH6J just trying, the pipe version worked fine, but when trying to pass a file I got an error:

clojure -X:viscous :file 150232_CARGUEROINOVACAO_VIACORRETOR.edn
Unreadable arg: "150232_CARGUEROINOVACAO_VIACORRETOR.edn"

wilkerlucio23:05:06

this works fine: cat 150232_CARGUEROINOVACAO_VIACORRETOR.edn | clojure -X:viscous :file -

wilkerlucio23:05:18

just realize it needs to be a Clojure string in the arg, this works: clojure -X:viscous :file '"150232_CARGUEROINOVACAO_VIACORRETOR.edn"'

wilkerlucio23:05:26

but the docs make believe the first should work

djblue23:05:13

If you a file or copied value, Portal can be used standalone https://djblue.github.io/portal/.

👀 1
wilkerlucio23:05:30

@U1G869VNV on that, this reminds me of a bug in Portal IntelliJ extension, when I accidentaly drag a file over it, it enters in the "drop zone" state and never leaves, not sure if you are aware of this one

wilkerlucio23:05:08

and yeah, the standalone is lovely, I really got used to the portal way of navigating data ❤️

djblue23:05:11

Wasn't aware :thumbsup:

djblue23:05:15

If you are a chrome user, you can install Portal as a PWA

wilkerlucio23:05:59

wow, thats cool 😄 just installed

awesome 1
phronmophobic23:05:03

@U066U8JQJ. Great catch! Merged. Thanks!

🙏 1
wilkerlucio23:05:21

@U1G869VNV is there a place with the shortcuts list on portal? I keep forgetting how to bring the command pallet there (suggestion: the shortcut could be in the hint message on the UI button, that way it gets easier to remember)

djblue23:05:57

They should be listed when you open the standalone app, :, ctrl + j or cmd + shift + p . The hint sounds like a good idea too :thumbsup:

wilkerlucio23:05:11

I'm blind, haha :man-facepalming:

wilkerlucio23:05:27

thanks, yeah, that solves it (looking at the home), I guess I got so used to the extension (that doesn't have the "home screen") that I didn't notice them in my face

djblue02:05:01

@U066U8JQJ https://github.com/djblue/portal/commit/b0ecdc3633a016f223c3aab60708394ae7035161 should fix the drop zone issue, not perfect, but good enough for now 👌

👍 1
lilactown22:05:47

what's the easiest way to create a custom exception type?

lilactown22:05:00

also, I'm doing something gross (using throw for something other than error handling), so I actually think it would be better to base it off Throwable than Exception ? not sure what consequences that might have tho

🤢 1
robertfw23:05:27

Sorry just catching up via threads, just saw there was further discussion

Joshua Suskalo15:05:45

@U4YGF4NGM using it for something other than error handling is fine. the JVM is well-built for it. It absolutely should not extend exception if it's intended to not be an error condition however.

Joshua Suskalo15:05:24

If you want a semantic type just extend throwable. If you want to have an explicit statement in the types that the value should not be caught by anyone except you, extend Error.

Joshua Suskalo15:05:26

This is exactly what I did for #farolero, which has a non-exceptional throw as well to provide early return.

lilactown16:05:21

@U5NCUG8NR I see you have a simple java class you wrote. how do you develop locally & package it for deployment?

lilactown16:05:45

I assume one has to compile the class for usage in clojure

Joshua Suskalo16:05:30

I use https://github.com/IGJoshua/americano , my simple java compilation library. It even supports git dependencies

Joshua Suskalo16:05:48

which means when I change the java class (which is almost never) I just run clj -X:build which compiles everything and then restart my repl.

lilactown16:05:29

this is exactly what I was looking for 😄

Joshua Suskalo16:05:38

Glad I could help!

lilactown16:05:23

I'm a bit ignorant of Java deps stuff. do you distribute the compiled artifacts in the JAR then when uploading your lib to e.g. clojars?

Joshua Suskalo16:05:52

yes, the compiled result needs to be in the jar when put onto a maven repository.

Joshua Suskalo16:05:15

only the java code should be compiled when put into clojars though, clojure code should be source-only

1
hiredman22:05:41

write some java

lilactown22:05:04

sounds like I would have to compile and load that, right?

ghadi22:05:16

What’s the reason to have a custom exception type?

lilactown22:05:51

I'm working on some gross internals of a framework

lilactown22:05:47

I need to signal from within a function that some parent context ought to skip whatever work the function is supposed to do and come back to it later

lilactown22:05:53

psuedocode:

(defn comments []
  (let [data (get-comments!)]
    (div
      (for [comment data]
        (div comment)))))

(defn page []
  (html
   (body
    (div
     (suspense {:fallback "Loading comments..."} (comments))))))

lilactown22:05:53

I want to, on first pass, signal from within comments that the parent ought to send the fallback to the client and start fetching comments. then after the comments data has been fetched, stream some special code that will replace the fallback with the comments markup

hiredman22:05:58

there is some new fancy clojure/clojurescript library that chops things up and streams things back and forth from client to server

lilactown22:05:31

yeah 😄 I got a demo of it earlier today

lilactown22:05:43

but this is for an existing project I'm trying to layer this on

lilactown22:05:09

I don't think that delimc et al. would work for me, because the reset boundary is outside the lexical scope of the shift in the code above, and that's necessary to Interop with existing code

emccue22:05:58

(Continuation/yield)?

lilactown22:05:37

loom continuations aren't reentrant so I don't think they would work for this case either

emccue22:05:43

oh actually (in thread)

emccue22:05:11

You could run the computation in another thread and use a channel to communicate that computation should suspend

emccue22:05:20

and wait for resume on another channel

lilactown22:05:41

but I need to signal to the parent to render the fallback first

emccue22:05:02

let me sketch

emccue22:05:37

(let [to-parent (chan)
      to-child  (chan)]
  (thread (try 
                  (do (<!! to-parent {:type ::come-back})
                      (!!> to-child)
                      (<!! to-parent {:type ::okay-done}))
                  (catch Throwable t (<!! to-parent {:type ::error :throwable t})
  (loop [result (<!! to-parent)]
    (condp = (:type result)
      ::error (throw (:throwable result))
      ::come-back (do (Thread/sleep 1000) (<!! to-child {}))
      ::okay-done nil))))

lilactown23:05:36

not sure I quite get it. but I think the ex-info approach works

lilactown23:05:11

like I don't understand from this sketch how that integrates with the pseudocode I posted. at the end of running the page function, I need a data structure that describes the HTML I should stream to the client. then I need to later stream some small JS code that replaces the fallback with the comments

lilactown23:05:09

rn i have some code that recursively walks the page tree, calling functions it finds until it has reached every leaf. I can in that code catch any errors and bubble that up to the nearest suspense boundary

lilactown23:05:01

this doesn't show me how I would handle that "stack" of boundaries, return the fallback, etc.

emccue23:05:55

i guess this just is a dumb way of doing a promise

emccue23:05:11

idk - ignore me

lilactown23:05:27

I appreciate the effort nonetheless! always happy to explore alternatives

hiredman22:05:46

I always forget that delimc does code transformation because core.match uses exceptions for jumps

lilactown22:05:30

I already have a lot of the machinery worked out. the way this works in React JS (which I'm copying the design of) is it throws a JS promise.

lilactown22:05:39

and the framework handles it

lilactown22:05:17

the way I want to do this is to throw a manifold deferred or something similar, but I can't do that because the type system is more strict

hiredman22:05:28

throw an ex-info

hiredman22:05:56

(throw (ex-info "please don't catch me :(" {:whatever ...})

lilactown22:05:34

if I catch an ex-info, check it for the payload, and if it doesn't have what I want re-throw it, will that mess with the stack trace?

hiredman23:05:11

user=> ((fn g [] (try ((fn f [] (/ 1 0))) (catch Throwable t (throw t)))))
Execution error (ArithmeticException) at user/eval2194$g$f (REPL:1).
Divide by zero
user=> (.printStackTrace *e)
Reflection warning, NO_SOURCE_PATH:1:1 - reference to field printStackTrace can't be resolved.
java.lang.ArithmeticException: Divide by zero
	at clojure.lang.Numbers.divide(Numbers.java:188)
	at clojure.lang.Numbers.divide(Numbers.java:3901)
	at user$eval2194$g__2195$f__2196.invoke(NO_SOURCE_FILE:1)
	at user$eval2194$g__2195.invoke(NO_SOURCE_FILE:1)
	at user$eval2194.invokeStatic(NO_SOURCE_FILE:1)
	at user$eval2194.invoke(NO_SOURCE_FILE:1)
	at clojure.lang.Compiler.eval(Compiler.java:7181)
	at clojure.lang.Compiler.eval(Compiler.java:7136)
	at clojure.core$eval.invokeStatic(core.clj:3202)
	at clojure.core$eval.invoke(core.clj:3198)
	at clojure.main$repl$read_eval_print__9110$fn__9113.invoke(main.clj:437)
	at clojure.main$repl$read_eval_print__9110.invoke(main.clj:437)
	at clojure.main$repl$fn__9119.invoke(main.clj:458)
	at clojure.main$repl.invokeStatic(main.clj:458)
	at clojure.main$repl_opt.invokeStatic(main.clj:522)
	at clojure.main$main.invokeStatic(main.clj:667)
	at clojure.main$main.doInvoke(main.clj:616)
	at clojure.lang.RestFn.invoke(RestFn.java:397)
	at clojure.lang.AFn.applyToHelper(AFn.java:152)
	at clojure.lang.RestFn.applyTo(RestFn.java:132)
	at clojure.lang.Var.applyTo(Var.java:705)
	at clojure.main.main(main.java:40)
nil
user=>

lilactown23:05:57

hmm ok maybe I'm being over cautious

lilactown22:05:58

I don't want to obscure real errors, which is why I was thinking of a custom type that extends Throwable

hiredman22:05:27

as someone who routinely catches Throwable, I don't put too much stock in the details of inheritance hierarchy under Throwable

lilactown23:05:31

but if I specifically caught my CustomThrowableWithExtraStuff it wouldn't muck with anyone

lilactown23:05:05

I'll go with ex-info for now