Fork me on GitHub
#clojure
<
2019-06-20
>
potetm02:06:34

isn’t that, like, the only tip?

potetm02:06:49

what other tip is there?

potetm02:06:42

the generalized form of the tip being: name your anonymous fns

andy.fingerhut02:06:24

Another: If you avoid naming your files core.clj, then the file name becomes more useful in the stack trace.

😄 4
andy.fingerhut02:06:01

Another, perhaps, but not for changing your code, but recognizing what is going on in a stack trace: What lazy function evaluation does to your stack trace, and why, and how to get the most info out of them anyway.

andy.fingerhut02:06:01

Maybe it's primarily a beginner thing, but some people really seem to be turned off by stack traces.

4
seancorfield03:06:37

FWIW, I'm loving the 1.10.1 basic error reporting with no stack trace 🙂

👍 4
seancorfield03:06:35

I mean, I can easily read full stacktraces -- I've been on the JVM for 22 years now so I've had to learn 😞 -- but a lot of problems can be solved from just the error message without the stacktrace.

seancorfield03:06:44

Interesting to see Stuart's anti-pretty-printer lib mentioned. I hadn't heard of that. I must admit I'm partial to what Aviso Pretty does, for the most part, but it could be improved.

andy.fingerhut03:06:43

I've not used it before -- forgot how I came across it. It stuck in my mind because of its somewhat non-obvious purpose.

seancorfield03:06:26

Now we have Throwable->map, maybe we can get more pluggability in terms of suppressing "irrelevant" frames?

andy.fingerhut03:06:33

I did fix one issue inside of Clojure itself where it took one exception and threw a different exception while trying to process it in some way (printing it, I am pretty sure).

andy.fingerhut03:06:08

So it definitely doesn't surprise me if some of the other pretty-printers have similar issues in some cases.

seancorfield03:06:43

Anything that manipulates an exception should be wrapped in a try/`catch` and if it fails, just throw the original exception again. But that's not reality I guess 😞

seancorfield03:06:41

clojure.java.jdbc has code to unwind stack traces to get at the underlying SQLException but that dated back to a time when there was unnecessary exception-wrapping in Clojure itself, as I recall? Since removed (so next.jdbc doesn't do this!).

seancorfield03:06:20

It would be an interesting exercise to make an interactive tool that takes a Throwable and lets you hide and show parts of it and explains what's important and what's not...?

andy.fingerhut04:06:24

As long as it doesn't throw an exception and erase your original 🙂

pinkfrog09:06:00

in the doc of `ensure’, it says, (def philosophers (into [] (repeatedly 5 #(ref :thinking))))

pinkfrog09:06:11

Allows for more concurrency than (ref-set ref @ref)

pinkfrog09:06:29

what does `more concurrency’ mean?

Alex Miller (Clojure team)10:06:38

The stm tracks the refs modified during a transaction. If you have a ref that is transactionally read, you need to cause a read-only ref to be included in the tracked refs

Alex Miller (Clojure team)10:06:16

One way would be with that ref-set, basically writing the ref by resetting to its current value

Alex Miller (Clojure team)10:06:03

The doc is saying that using ensure (instead of deref) to read a ref and include it in the tracked ref set allows the stm to be smarter about failing one of two transactions that only read a ref

Alex Miller (Clojure team)10:06:02

In that case, there is no conflict and both txns can proceed, allowing greater concurrency

Maciej Szajna10:06:56

Hi! I was going to file a bug against clojure but wanted to double check. The code below blows up (clojure 1.10.0)

(try
  (loop [] (try 1 (catch clojure.lang.ExceptionInfo e)))
  nil
  (finally))

=> Syntax error (ClassFormatError) compiling fn* at (REPL:1:1).
=> Illegal exception table range in class file user$eval5846
While this doesn't (replaced the 1 with ())
(try
  (loop [] (try () (catch clojure.lang.ExceptionInfo e)))
  nil
  (finally))
=> nil

andy.fingerhut16:06:34

I would not be surprised if there is already a ticket filed about the root cause, but you are welcome to file a ticket, and if someone finds a related issue, they will likely link the issues together, and/or close one.

andy.fingerhut16:06:57

The good news is that it is failing to generate code, instead of successfully generating wrong code, at least in your example 🙂

vemv16:06:29

What's with stealing a busy man's attention with a beginner question? Really inconsiderate. And you'd get the same answer from this channel without having to tag anyone.

hulunote10:06:51

should be the result be 1 in this case?

bronsa10:06:54

yes, that behavior is correct, clojure tests for the interned booleans only

bronsa10:06:56

Note that if does not test for arbitrary values of java.lang.Boolean, only the singular value false (Java’s Boolean.FALSE), so if you are creating your own boxed Booleans make sure to use Boolean/valueOf and not the Boolean constructors

orestis13:06:51

What’s your favorite Excel document generation library? All of them seem to be based off Apache POI but most of them are on an old version – and that API is really horrible to write directly via interop.

mpenet13:06:21

didn't cgrand worked on something for that?

mpenet13:06:32

ah no, I think it was something else. There seem to be https://github.com/mjul/docjure tho

cgrand13:06:45

nope, it was about using excel spreadhseets as functions

cgrand13:06:17

I should try to wrap them in a Lambda now 😉

orestis13:06:35

Yes it seems docjure is the most popular and there is some effort to bring it to a recent version of POI

orestis13:06:58

There was an excellent talk some years ago about using Excel files as templates… need to find that.

mpenet13:06:58

can't say if it's good or not, never had to use it

orestis13:06:41

This has a much more data-oriented API: https://github.com/matthewdowney/excel-clj --- docjure seems a bit.. imperative.

hoynk15:06:22

I have a silly question: why is the convention for cond (and friends) when one cannot use its short form not to ident the code under the condition? (https://github.com/bbatsov/clojure-style-guide#shor-forms-in-cond)

seancorfield16:06:08

Pretty much, yes. Basically, in Clojure, when we see:

(something ...
    (another-thing ...
we assume that (another-thing ...) is an argument of some sort to (something ...) -- indentation implies nesting. It's at the core of parinfer, for example.

hoynk16:06:04

I understand, but this still seems weird. Not having parenteses around the condition/form pairs was I think, just so there would be less parenteses around. Common Lisp's cond, for example, do have them.

seancorfield16:06:46

You get used it to pretty quickly and the "stacked" alternation of condition / result / condition / result reads well.

hoynk17:06:07

Hope so. Thanks for answering such a silly question 🙂

seancorfield17:06:26

There are no "silly" questions (there are silly answers tho'!).

Felix Linker16:06:41

Can you think of a nice way to interleave two unbalanced lists? Like so: (= (interleave2 '("a" "b" "c") '(1 2)) ("a" 1 "b" 2 "c")). My first thought was to use vectors, add a nil element to the second vector and pop that but I now figured out that I need lists and don't want to do casting over and over. So something linke interpose but where the delimiter is pulled from a coll.

hiredman16:06:48

The thing is, there are different ways you might implement interleave-all

hiredman16:06:46

You might cycle the shorter collection, or once you run out of elements in the shorter, just make the rest of the seq the rest of the longer

hiredman16:06:51

And it isn't casting

djtango17:06:58

has anyone seen this before?

dev=> (compare "foo" (java.time.Instant/now))                   
Execution error (ClassCastException) at (REPL:1).
null
dev=> *e
#error {
 :cause nil
 :via
 [{:type java.lang.ClassCastException
   :message nil}]
 :trace
 []}

djtango17:06:24

the lack of trace was a little unhelpful...

ghadi17:06:52

certain traces can be elided by the JVM when things are optimized

ghadi17:06:07

@djtango the full message would probably have been more helpful

ghadi17:06:58

here's a demonstration of that:

andy.fingerhut21:06:35

@U050ECB92 Thanks for that demonstration code. I have been running some experiments of behavior with a few different JVMs to confirm they are consistent, and getting run times as well, with and without the -XX:-OmitStackTraceInFastThrow option.

andy.fingerhut21:06:53

The runtime are much longer with that option, but of course with the benefit of preserving the full stack trace.

andy.fingerhut21:06:03

Regarding the much longer run times, this demo code is throwing an exception on every iteration through the dotimes. Would you expect this to be atypical code, throwing an exception all of the time? I am guessing it would be more typical to have code in a tight loop that usually runs fine without throwing an exception, but once in a blue moon, it does, and that is when you want the full stack trace preserved.

andy.fingerhut21:06:22

In a different variant of this demo code, where it runs many times with no exception thrown, and only then I call it again in a way that causes the exception, the time results are much faster, because only a handful of calls to the function f cause the exception to be thrown, not all of them. Seems like a less scary performance number to report in an article, for example.

ghadi17:06:54

it took a few times, but then the JVM decided, to hell with generating a full stacktrace

ghadi17:06:38

-XX:-OmitStackTraceInFastThrow

hiredman17:06:41

there is a flag you can pass to the jvm to turn off eliding stacktraces, which I've never seen not used on large projects

hoynk17:06:20

Could you point me to that, please?

djtango17:06:58

-XX:-OmitStackTraceInFastThrow

andy.fingerhut18:06:05

Another good tip for an article on JVM stacktraces for Clojure developers. Collecting some info...

ghadi17:06:48

^ that's the one

djtango17:06:37

I see - thank you! That will possibly explain why I've also seen similar behaviour exhibited in an arithmetic-heavy program?

hiredman17:06:00

it is basically the only way you get exceptions that are missing information like that. in theory some other program could be intercepting the exceptions and trimming them, but I've never encountered that, only the jvm deciding to optimize things and trim out the information

djtango17:06:24

fair enough - thanks for the help. Do you leave this on in prod?

seancorfield17:06:16

Yeah, we have that option on in production. Otherwise, if anything goes wrong, we have no stacktrace to log 😐

seancorfield17:06:50

I think it's a silly default. I have to remember to include it in every new piece of "run Java/Clojure" infrastructure that I setup.

ghadi17:06:41

it's not on all exception types, IIRC

ghadi17:06:49

but definitely ClassCast and NPE

jumar11:06:46

It applies only to a handful of exceptions like NPE, ClassCast, ArrayIndexOut, NumberFormat, and ArrayStore. And usually only if your code (or library) follows a bad programming style.

seancorfield15:06:06

"Bad programming style" -- but NPE and Class Cast are probably the most common Clojure errors people complain about 🙃

hiredman17:06:46

clojure's runtime certainly doesn't do it

vemv17:06:06

this is ruby

vemv17:06:15

can clojure have an arbitrary system like that?

vemv17:06:23

that prints the command output's colors automatically

vemv17:06:32

(I am aware of clojure.java.shell/sh)

noisesmith17:06:21

if you use shell/sh inside a real terminal, the coloration will work as expected

noisesmith17:06:04

the next problem is that shell/sh creates a condition that will turn off colorization for many commands by default - I don't know how ruby gets around this

vemv17:06:03

works, yes thanks! yeah I vaguely recall having to add --color only under certain conditions

noisesmith17:06:20

I think it might be checking if stdin is closed?

noisesmith17:06:25

I'll do more research

noisesmith17:06:33

With --color=auto, ls emits color codes only when
standard output is connected to a terminal.

noisesmith17:06:12

I think this is the typical logic, and shell/sh outputs to a string rather than the terminal directly

vemv17:06:41

good find!

vemv17:06:51

ahahaha didn't know ProcessBuilder was a thing either (I do recall though that between clojure.core and java.lang there are around a thousand "refered" things in a given ns)

noisesmith17:06:57

ProcessBuilder is in java.lang, and it's what clojure.java.shell/sh uses. It's actually a decent API that's better than any of the clojure wrappers I've seen.

👍 4
noisesmith17:06:25

especially if you need to use interactive features (connect the command's stdio to your terminal, or send new input as you read the command's output)

noisesmith17:06:12

eg. there's the conch library that tries to turn the io into lazy-seqs, but if what you want is dynamic process IO the lazy-seq abstraction just makes things more complex

👍 4
noisesmith17:06:54

a case where the defaults for raw interop are more convenient than our wrappers

Felix Linker18:06:26

Can someone give me the story for why clojure.contrib went deprecated and now for example basic math functions are in ? I mean, it appears hilarious to me that I have to include a dependency in order to use abs :face_with_rolling_eyes:

seancorfield19:06:17

This page touches on it a little https://clojure.org/community/contrib_history but it mostly came down to the fact that of the 60+ pieces in Monolithic Contrib, only a handful actually had active maintainers and the nature of clojure.contrib meant that all those pieces got released together (and essentially in lockstep with Clojure itself). Breaking it up meant those pieces could move forward at their own pace and it would be clear which ones had active maintainers and which didn't.

🙏 4
seancorfield21:06:57

Oh nice! I didn't realize that piece had found it's way onto http://clojure.org -- thank you!

Alex Miller (Clojure team)22:06:48

I moved all of the vaguely relevant things on the old blog into the news items

💯 8
dpsutton18:06:23

Math/abs should be handy for you

Felix Linker18:06:51

Ah. Yes. Because there is java interoperability 😄

dpsutton18:06:11

host language 🙂

csd19:06:39

Might anyone have any idea why I'm getting a java.lang.NoClassDefFoundError for javax/servlet/http/HttpUpgradeHandler when compiling ring/adapter/jetty.clj? My project.clj does include [javax.servlet/servlet-api "2.5"], which I think is supposed to address similar errors. Googling isn't returning instances of people running into this exact issue, although the above import is supposed to fix similar class no defs.

noisesmith19:06:04

one thing I find is that javax.servlet is superceded by javax.servlet-api

noisesmith19:06:35

2.5 is a 12 year old version of that lib

csd19:06:51

interesting. switching fixed it

seancorfield19:06:17

This page touches on it a little https://clojure.org/community/contrib_history but it mostly came down to the fact that of the 60+ pieces in Monolithic Contrib, only a handful actually had active maintainers and the nature of clojure.contrib meant that all those pieces got released together (and essentially in lockstep with Clojure itself). Breaking it up meant those pieces could move forward at their own pace and it would be clear which ones had active maintainers and which didn't.

🙏 4
seancorfield19:06:02

Also, re: math.numeric-tower -- that exists to offer polymorphic math functions across all of Clojure's numeric types, which is far beyond what something like Math/abs offers, but is also a rather specialized use case: to want math.numeric-tower you need to be writing generic math-based code that should operate across the full range of types.

🙏 4
Alex Miller (Clojure team)22:06:34

Clojure Applied has some stuff on it, depends what your goal is