This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-04-03
Channels
- # aws (5)
- # beginners (67)
- # boot (30)
- # cider (55)
- # clara (7)
- # cljs-dev (6)
- # cljsjs (6)
- # cljsrn (1)
- # clojure (136)
- # clojure-brasil (2)
- # clojure-dusseldorf (14)
- # clojure-finland (9)
- # clojure-italy (49)
- # clojure-nl (1)
- # clojure-romania (6)
- # clojure-russia (4)
- # clojure-uk (16)
- # clojurescript (136)
- # core-async (1)
- # cursive (21)
- # datomic (64)
- # fulcro (26)
- # hoplon (25)
- # jobs-discuss (53)
- # keechma (3)
- # leiningen (6)
- # luminus (11)
- # lumo (2)
- # off-topic (351)
- # om (1)
- # onyx (11)
- # parinfer (32)
- # portkey (9)
- # re-frame (45)
- # reagent (38)
- # shadow-cljs (60)
- # specter (9)
- # vim (8)
- # yada (22)
Okay so I have a fun one for the room - is there a way to hint a clojure reify to emit a void method? I don’t know of one.
And yes it’s strange
There’s a ^void you can use - I’ve run into this once or twice
the bytecode is still not optimal though - it basically creates the return value and throws it away
@alexmiller does that affect performance? Seems like the JIT could remove that
it does - I ran into this on an alioth program
it’s not big, but it’s not 0
admittedly, this was several jdks ago now though
Does anybody know how to handle errors/exceptions in Clojure? especially if I have a function composition like
(->> (f x)
(g)
(h))
and every function can throw an error/exception, but I only want to call the next function if no error is thrown. Any ideas?That's how exceptions work. They interrupt the flow of execution and exit all the call frames until they meet a matching catch
block
But beware of laziness; if an exception occurs in a later element of a sequence, it may not be caught until some later processing has already occurred.
A simple fix is to sprinkle your pipeline with doall
s
a rule of thumb i read a long time ago: - exceptions: the programmer did something wrong. e.g. assertions, network failure, etc. - errors (aka just a different kind of return data): the user did something wrong. exceptions do provide one nice feature; fast failure. e.g. buddy-auth uses exceptions to short-circuit auth failures to bypass the ring middleware stack quickly.
https://github.com/cognitect-labs/anomalies may be of interest to you @denisgrebennicov
There's monad-y stuff you can do like this: https://adambard.com/blog/acceptable-error-handling-in-clojure/
bottom line: errors are just another kind of data. the language doesn’t need to do something special. i spoke on this in my most recent post, with the check-n pattern: https://www.stuttaford.me/2018/03/31/bridge-dev-diary--events-api/
I went through a phase a few years ago when I thought that was more functional and thus better
These days I like to just throw around ex-info
and be done with it
I suppose it depends on your specific case
@pesterhazy I was reading the good enough blog post right now 😄 Interesting ideas
one very frequent occurrence is for something to return nil instead of whatever you expected, and so we have some->
and some->>
macros to handle early-stop-on-nil
(if-some [val (some->> lookup-ref (d/entity db) :some/key)] … {:status 404})
sort of thing
it's only when you need to keep track of the kind of error you encountered when the more complex stuff is needed
e.g. to provide error messages to the user
yep. that’s what i’ve specifically decided to do in bridge
What's the pattern for mapping over a nested list? i.e. We have [[1 2 3] [4 5 6]]
and we want as an output [[2 3 4] [5 6 7]]
? mapcat
would flatten the inner lists, which we don't want, but our existing (map #(map ...
is just hideous
@carr0t That would be it yes. In other functional programming languages this might be expressed as repeated fmap and looks a bit less hideous, but they do it all the time.
x = [[2, 3, 4], [5, 6, 7]]
(fmap . fmap) (+1) x -- [[3,4,5],[6,7,8]]
(mapv (partial mapv fun) xs)
if that's ugly in your book, I'm happy to write ugly code
user=> (defn mapv2 [f xs] (mapv (partial mapv f) xs))
#'user/mapv2
user=> (mapv2 - [[1 2] [3 4]])
[[-1 -2] [-3 -4]]
hey guys, does anybody know if it is possible to avoid getting two different exceptions whenever the compiler find an error? See example below. This gets really problematic the bigger the spec error is since you get two huge prints for a single error. Ideally I would like to limit it to a single error 🙂
(let [1 2])
clojure.lang.ExceptionInfo: Call to clojure.core/let did not conform to spec:
In: [0] val: () fails spec: :clojure.core.specs.alpha/bindings at: [:args :bindings :init-expr] predicate: any?, Insufficient input
clojure.lang.Compiler$CompilerException: clojure.lang.ExceptionInfo: Call to clojure.core/let did not conform to spec:
In: [0] val: () fails spec: :clojure.core.specs.alpha/bindings at: [:args :bindings :init-expr] predicate: any?, Insufficient input
#:clojure.spec.alpha{:problems [{:path [:args :bindings :init-expr], :reason "Insufficient input", :pred clojure.core/any?, :val (), :via [:clojure.core.specs.alpha/bindings :clojure.core.specs.alpha/bindings], :in [0]}], :spec #object[clojure.spec.alpha$regex_spec_impl$reify__2436 0x5b77ed8c "clojure.spec.alpha$regex_spec_impl$reify__2436@5b77ed8c"], :value ([a 2 b]), :args ([a 2 b])}, compiling:(/Users/Camilo/Proyectos/kamal/src/hiposfer/kamal/dev.clj:55:1)
@ghadi I am using it, that is where the problem came from 😄. See https://github.com/bhb/expound/issues/81#issuecomment-378240072
Unfortunately Expound only aggravates the problem since by pretty printing it you use much more space than what Clojure originally printed 😕 . Although the output is clearer there is still lots of noise
in general, you can usually ignore all but the root cause exception in Clojure (the CompilerException in particular is nearly always a wrapper solely to transmit file/line/col info)
@alexmiller but that would require me to catch the exception and then look for the root cause, which although can work is not the intended scenario. I am not sure if this is a Cursive problem or from Clojure but at least in Cursive if I type (let [1 2])
I get two exceptions printed in the console, not one as in every other case. It is not the case that I get one exception inside another but rather 2 different repl-returned exceptions for the same code execution. Hope that makes it a bit more clear 😅
that seems weird. my typical experience in Cursive is that I see just the top exception (which is never the one with the correct information about the cause), so I typically call pst to get that
maybe the outer exception here contains a message that includes the output from printing another exception
it seems that you were right. If I do *e
I get the full error which includes the two errors that are being displayed. So this is probably an IDE/tool parsing problem not a repl one
@denisgrebennicov I used some macros in Vase to make nested try/catches with values less ugly. https://gist.github.com/mtnygard/c786c67f5bb98cac883116c45330158c Basically lets me avoid doing (try (let [] (try (let [],,,
when I run jps -lv
from command line, even after closing down my repls, i see an entry there for clojure.main ...
what is it?
If you're on Windows and using lein or cider-jack-in from emacs, I've noticed that 1 of the 2 JVMs don't always exit.
hey, I need to test out an error serialization function.. what's a simple operation in vanilla clojure that's guaranteed to throw?
In practice how do reference types and core.async interact? It seems like they solve the same or similar problems in different ways. Does core.async obviate a lot of the need for reference types or are there common patterns where they can be useful together?
yeah they seem orthogonal concepts, can you explain why you think they're solving the same problem?
the reference types are about identities, core.async is about communicating processes
There's a little overlap between agents and CSP, I wish there could be more. A lot of times what people use CSP for could be replaced with agents, if agents supported backpressure
But even then agents are communication via sending mutation functions to a reference type. While CSP is about sending messages to a process.
It seems to me that they're both tools for managing shared state in concurrent systems. So if I have a resource that multiple parts of a program need access - like a map that serves as an in memory database - I should access it via either: * Having a process which owns it and other processes communicate with or, * Holding it in a reference type which different threads can access.
I guess what I'm really asking is how are both used together in systems and does anyone have any examples?
@naylyn.gaffney Perhaps one difference is that with reference types, it is explicit in Clojure design that anyone can read the current value at any time, without blocking or consuming any resources from any other thread.
If you need to send a message to some central place to read, that is quite different.
If you have a java jar with a com.foo.bar.Main and want to invoke main, how do you do that inside clojure?
no, it would be (com.foo.bar.Main/main)
on the jvm, similar to C, there is a static main method that is used as the entry point, if Main doesn't have that, it isn't designed to be the initial entry point of the program
is this main function required to accept arguments or is a no-arg arity acceptable? it seems to be in my experience but can't find any official doc on that
interesting. I frequently see -main written with arity of [& args]
. i don't know Java much but var-arg seems different to me than a single arg that is an array?
oh, yes sorry
I should have said that :)
I also should have caught that. Had do to something similar for finding files (into-array FileAttribute [])
or some such.
Cool. Using deps.edn, I can load a bunch of peer services into a single JVM for demo purposes.
is this main function required to accept arguments or is a no-arg arity acceptable? it seems to be in my experience but can't find any official doc on that
in Java, it is varargs, so 0 is ok
but Java varargs in Clojure are represented as an array, so it’s 1-arity when invoking via interop
Question re: transducers. I keep reading they avoid the collection of intermediate results, and that otherwise composing sequence transformations e.g. map, filter etc. results in realizing intermediate results. But since those transformations are lazy, isn't the extent of any intermediate collection relegated to just whatever chunksize is pulled through in the thunk?
If that's the case, then you don't really save much on memory, right? Maybe just the computational overhead of setting up the thunks
In their fully applied sequence arities yes those operations are lazy and produce lazy sequences. As transducers they’re streaming operations which get forced eagerly when you use transduce
.
Right - so when I continually read that transducers avoid collecting intermediate results, that's kind of half true no?
For example: (filter even? (map inc (range 100)))
is not going to generate 100 results before passing to filter
I think the emphasis on efficiency gains probably pertains more to the time saved by avoiding building up thunks
Sure but that’s the lazy sequence path. If you (transduce (comp (map inc) (filter even?)) conj [] (range 100))
, that (range 100)
will yes get lazy sequence chunked, but as it does so the transducer stack (the comp) will be eagerly driven element-at-a-time over the input.
there'll be 32 at every point in the pipeline though. so (->> (map inc) (filter odd?) (remove pos?) (map dec)) = 96 + the overhead of tracking 3 computation promises
it's really more about abstraction and generalizing to any input than making it faster then
(transduce (comp (map inc) (filter even?)) conj [] (range 100))
Compiles down to something that looks really close to a for loop in Java
range
never creates a cons cell and neither to the transforms
it’s the creation of all the intermediate cons cells that takes the memory in the lazy-seq case
yeah I wouldn't say "pretty limited". it's a whole mess of big extra object graphs. also really depends on the size of the items you're iterating over
(into [] (comp (map inc) (filter even?)) (range 100))
is even better, because in this case you create almost no garbage at all, In this case transients remove the garbage created by conj
for (object i = 0; i < 100; i++)
{
v = i + 1
if (even?(v)) lst.append(v);
}
that's about what that transducer pipeline executesand yeah garbage collection of all those interim things is significant. java garbage collection is fast but not as fast as no gc at all
The problem is also GC pressure, I've worked on many systems that execute fine in isolation, but all that "fast allocation" adds up in the end to a system that has GC pauses every 20 sec.
Allocation is almost free on the JVM, GC is not
Got it, appreciate the clarifications. I was coming it at from the perspective of trying to choose whether it's worth it to move to transducers from a current pipeline of lazy transformations on 100's of gigs.
In that case? Very recommended, but for one more reason as well:
It's almost impossible to hold onto the head of a collection with transducers. And its' really hard not to with seqs.
So one cool thing with processing that amount of data. Reducing functions, like conj, can be replaced by anything that wants a stream of stuff. clojure.lang.IReduceInit
can be implemented on almost anything that produces a sequence of stuff. So I've written pipelines that do stuff like this:
(transduce
xform
append-line
(file-writer "file")
(file-reader "ifile"))
And with that there's no way you can mess up and hold on to something. Also you can replace parts of that with clojure.core.async/pipeline-blocking
and then you can get parallel transforms.
So one CPU reads, another writes, and the rest transform.