clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
lilactown 2021-03-22T15:16:58.295400Z

what's the best way to check to see if an object is an error?

lilactown 2021-03-22T15:17:04.295600Z

(instance? Exception v*) ?

lilactown 2021-03-22T15:18:42.295800Z

maybe (instance? Throwable v*)

nilern 2021-03-22T15:19:56.296800Z

I think any other method would just wrap that instance check

nilern 2021-03-22T15:22:39.299500Z

You should not (catch Throwable ... so (instance? Throwable ... might not be a good idea

nilern 2021-03-22T15:26:10.300200Z

OTOH Errors definitely are errors

nilern 2021-03-22T15:29:22.302Z

And then there are non-`Throwable` error values like https://cljdoc.org/d/com.deepbeginnings/monnit/0.1.2/api/monnit.result#Err (shameless plug) If you need to support those then a protocol or multimethod would be in order

lilactown 2021-03-22T15:31:17.302500Z

:thinking_face:

user> (instance? Error (ex-info "" {}))
false

lilactown 2021-03-22T15:31:50.303100Z

user> (instance? Exception (ex-info "" {}))
true
user> (instance? Throwable (ex-info "" {}))
true

nilern 2021-03-22T15:32:10.303600Z

ExceptionInfo extends Exception extends Throwable

nilern 2021-03-22T15:32:18.304Z

Error extends Throwable

lilactown 2021-03-22T15:32:47.304400Z

sounds like I should check for Throwable then

nilern 2021-03-22T15:35:44.305800Z

It depends. I guess you are doing something like (let [v (<!! chan)] (if (error? v) (throw v) v))?

Ben Sless 2021-03-22T15:39:36.308Z

Is there a way to bind dynamic variables in macro expansion? Something like

(def ^:dynamic *dyn*)

(defmacro foo
  []
  (binding [*dyn* 1]
    `(bar)))

(defmacro bar
  []
  (let [v *dyn*]
    `(println ~v)))

nilern 2021-03-22T15:39:49.308200Z

I think Throwable would be right in that case but in practice something funky is going on if there is an Error as a value

lilactown 2021-03-22T15:42:42.308700Z

yes exactly 😄

nilern 2021-03-22T15:46:17.309Z

I don't think so. The compiler calls macros in a kind of prewalk so by the time bar expands foo has already returned. Or you could call macroexpand yourself in foo but that is going into Racket-level macro-fu

nilern 2021-03-22T15:53:57.309400Z

But you can give bar extra parameters that end-users might never pass but foo does. Or maybe bar is not even public. As a Schemer that is how I would approach this e.g. http://synthcode.com/scheme/match.scm

nilern 2021-03-22T15:54:33.309600Z

;; This is the guts of the pattern matcher.  We are passed a lot of
;; information in the form:
;;
;;   (match-two var pattern getter setter success-k fail-k (ids ...))
;;
;; usually abbreviated
;;
;;   (match-two v p g+s sk fk i)
;;
;; where VAR is the symbol name of the current variable we are
;; matching, PATTERN is the current pattern, getter and setter are the
;; corresponding accessors (e.g. CAR and SET-CAR! of the pair holding
;; VAR), SUCCESS-K is the success continuation, FAIL-K is the failure
;; continuation (which is just a thunk call and is thus safe to expand
;; multiple times) and IDS are the list of identifiers bound in the
;; pattern so far.

(define-syntax match-two

nilern 2021-03-22T15:58:25.309800Z

But of course fancy macro tricks are not idiomatic in Clojure

Ben Sless 2021-03-22T16:03:00.310200Z

So my options are either writing my own code walker or an anaphoric macro

Ben Sless 2021-03-22T16:03:21.310400Z

not thrilled about either

lilactown 2021-03-22T16:11:23.312100Z

I ended up solving this a different way. My use case is I have two core.async channels, one for errors and one for success. I ended up doing this:

(a/go
             (let [[res c] (a/alts! [error-chan complete-chan])]
               (if (= c error-chan)
                 (reject res)
                 (resolve res))))
so instead of asking whether it's instance? of something, I just check to see if it came from the error-chan

lilactown 2021-03-22T16:12:08.312700Z

elsewhere I have a try / catch in a go-loop that chooses whether to put on the error-chan or complete-chan

lilactown 2021-03-22T16:13:43.312800Z

yeah it's a bummer

Ben Sless 2021-03-22T16:17:04.313Z

btw, you can use identical? when checking the returned channel from alts

Ben Sless 2021-03-22T16:17:16.313200Z

It's really apropo of nothing, just slightly faster

lilactown 2021-03-22T16:21:55.313400Z

👍:skin-tone-2:

zendevil 2021-03-22T17:51:13.315500Z

Suppose I have the following map: {:user/goo 1 :user/bar 8 :user/foobar 9 :content/foobarbaz 10}. Is there a way to get the contents of just the namespace :user/ from this map?

seancorfield 2021-03-22T17:52:26.316500Z

Probably the easiest would be to reduce-kv over it and check (if (= "user" (namespace k)) (assoc m k v) m) as the 3-arity reducing function.

2021-03-22T17:54:06.317400Z

There's filter-keys from medley if you want to bring in a util library https://weavejester.github.io/medley/medley.core.html#var-filter-keys (or you could just name @seancorfield's function accordingly)

ghadi 2021-03-22T17:54:56.318Z

a filter-keys predicate could be something like (comp #{"name"} namespace)

ghadi 2021-03-22T17:55:19.318400Z

...ok then

😅 10
em 2021-03-22T18:03:10.319300Z

comp was too powerful

lassemaatta 2021-03-22T18:05:07.319500Z

just imagine what would have happened if someone suggested a solution based on juxt...

😄 1
zendevil 2021-03-22T18:31:08.320Z

p-himik 2021-03-22T18:36:37.320900Z

@ps There's no need to leave and join channels if you find them too noisy but still want to use them - you can just right click on a relevant channel and mute it.

ericdallo 2021-03-22T18:40:05.322200Z

Hello, it seems a noob question, but how can I run a alias after another with clojure cli? Like run a alias uberjar and then my-other-task

clj -X:uberjar:my-other-task

2021-03-23T20:02:31.379500Z

You think tools.build will focus only on command line orchestration? I feel it will also bring along common tasks, a common config format and a standard data exchange for them, but hopefully where tasks are still just Clojure command line apps.

seancorfield 2021-03-23T20:19:24.380100Z

I didn’t say it would “focus only” on that. I just expect it to deal with chaining some sort of set of tasks — in a well-designed manner — as part of whatever it brings to the table.

2021-03-23T20:24:00.380300Z

Oh ya for sure.

ericdallo 2021-03-22T18:40:16.322300Z

this seems to run only the last one

2021-03-22T18:52:40.323200Z

I wouldn't expect it to run multiple aliases in one invocation, for one thing each alias is allowed to define the classpath differently

seancorfield 2021-03-22T18:52:48.323400Z

Only one “main” or “exec” operation can happen — and these are merged in last-one-wins form.

2021-03-22T18:53:15.323600Z

and unlike lein (where the lein do command does what you describe) clj doesn't spawn multiple vms to make that possible

seancorfield 2021-03-22T18:53:21.323800Z

(I would expect tools.build to address this sort of thing in some form since it’s such a common ask)

seancorfield 2021-03-22T18:53:59.324Z

This is why we currently have a build shell script at work that runs clojure multiple times, with each group of command-line args in turn.

ericdallo 2021-03-22T18:54:05.324200Z

yes, I just would like to be able to run a alias after another

ericdallo 2021-03-22T18:54:42.324400Z

yeah, maybe I'll need to go with clj -X:jar && clj -X:my-other-task

ericdallo 2021-03-22T18:55:07.324600Z

this is related with this new lib I'm creating: https://github.com/ericdallo/deps-bin

seancorfield 2021-03-22T18:55:14.324900Z

We’d also prefer folks to show some patience when posting a question in one channel instead of cross-posting it almost immediately to another channel @ps

ericdallo 2021-03-22T18:55:31.325200Z

I'd like to sugest to user generate the jar with depstar and then call the bin with:

clj -X:jar:bin

seancorfield 2021-03-22T18:59:59.325700Z

Since you don’t need interactivity, you might suggest clojure -X:jar && clojure -X:bin to avoid a layer of rlwrap around each command.

seancorfield 2021-03-22T19:00:46.325900Z

FWIW, in “My Deployment Process” in the depstar readme, I suggest exactly that sort of thing although I realize it probably won’t work on Windows(?).

1
ericdallo 2021-03-22T19:00:51.326100Z

alright, thanks for the help @seancorfield and @noisesmith!

ericdallo 2021-03-22T19:01:28.326400Z

hum, good point

seancorfield 2021-03-22T19:02:05.326600Z

Even worse: doing this causes noise for others because of the join/leave messages 😞

vemv 2021-03-22T20:19:33.327100Z

> Even worse: doing this causes noise for others because of the join/leave messages I've seen those disabled in other slacks. Personally I liked that b/c someone leaving a channel tends to have a negative connotation (however slight)

seancorfield 2021-03-22T20:29:37.327400Z

@vemv It’s very useful for Admins to see the joins because that makes it easier for us to spot folks who join and immediately start posting without getting the lay of the land. Unfortunately, we can’t easily have it enabled for Admins but disabled for everyone else I think.

👍 1
seancorfield 2021-03-22T20:31:17.327600Z

I’ve turned it off for now but we (Admins) may turn it back on if it inhibits our ability to deal with bad actors.

👍 1
2021-03-22T21:17:08.328Z

Just write a Clojure script to do it

2021-03-22T21:21:07.328200Z

Like build.clj and then clojure -X:build-task which is an alias to some function in build.clj that orchestrates whatever build you want.

👍 1
1
seancorfield 2021-03-22T21:38:04.328500Z

Or, maybe, wait and see what tools.build brings? 🙂

👀 1