Fork me on GitHub

I see, and there’s never going to be one size fits all here 🙂


Thanks again, I’ll go at implementing some of this stuff and see where I end up.


At work, for a lot of validation, we use clojure.spec but at this stage you may want to start off with something more basic?


Yes, I’ve been looking at spec since yesterday, I’ll probably keep at it but it hasn’t quite sunk in yet. I will certainly try it out for validation on this use case. One thing I did notice from reading yesterday was when creating a spec for a map you specify req and opt keys which got me wondering what if I had a map with :email and :phone keys and that entity/record is valid if at least one of those are available? That wouldn’t fit in with the spec/keys macro as they could both be either required or optional, does spec have a way to describe this sort of thing?


Spec is arbitrarily predicative, so you can compose any predicate with an s/and. You example would be something like this:

(s/def ::person (s/and (s/keys :req [] :opt [::email ::phone])
                       #(or (::email %) (::phone %))))
You even get correct generation this way.

❤️ 4

I also need to work out how to parse the output of conform, but I may just get it working with valid? first 😄


Hello All!! So I've been working on my clojure knowledge and now I am on a good ground to keep further developing my skill. One thing I am particularly puzzled is about life time of immutable objects. I looked at Brian Beckman's talk with Rich Hickey where he explains how datastructures get extended. And my question is, clean up exclusively dependent on host's garbage collector? What about captures? Once an object is captured when is this object released?


this is something all garbage collectors need to handle, clojure doesn't implement it at all (though it does have "locals clearing" in the closures it creates to help free things sooner)


makes sense.


a captured object is released when the thing that captured it is released


@matt.henley s/keys -- you can specify or with alternate keys; you can also specify them both as :opt (or more likely :opt-un since I think you're dealing with unqualified keys?) and then s/and around the s/key to add a predicate that checks at least one of those keys is present.

Abhinav Sharma03:10:29

Hello Clojurians, I need a bit of help regarding connecting the figwheel-main CLJS repl working properly with Cursive. I’ve followed the instructions and the dev build completes, browser opens up and I’m able to interact with pure CLJS commands in the REPL. However, anything related to js/ namespace or even *clojurescript-version* doesn’t work.


Alert is only going to be available from a browser

Abhinav Sharma03:10:44

Yup, but it’s not popping up at all. Neither are any (js/console.log "something")

Ashutosh Soni10:10:10

@U2BU9G0LT is anything mounted on localhost ?

Abhinav Sharma10:10:28

Yes, the default figwheel app is there and it sows correct info on the console

Abhinav Sharma10:10:37

As in, session connected and name.


Hi, I am using buddy authentication lib. And whenever I try to decrypt my message I get ArrayIndexOutOfBoundException (the code and the stack trace is in the snippet). Why is that ?Am I using the wrong encryption algs. Created my key by these commands :

openssl genrsa -aes256 -out privkey.pem 1024
# Generate public key from previously created private key.
openssl rsa -pubout -in privkey.pem -out pubkey.pem


What type of value is pubkey in your code? The examples for using buddy that I see take a hash of some value as a key


I created them using (buddy.core.keys/public-key "resources/keys/pubkey.pem") and (buddy.core.keys/private-key "resources/keys/privkey.pem")


You're right the examples in buddy-sign use hash values yet the examples in buddy-auth use keys imported using buddy.core.keys


Your code is using the pub key for encrypting and decrypting, you likely need to use the private key for decrypting


Oh Sorry thanks alot @hiredman


hi! dumb question. Is the continuous use of -> and --> idiomatic?


They’re incredibly handy, and completely idiomatic, so use them as much as you like. For getting data out of a nested map, get-in does have conveniences that beat -> though. Particularly with the last parameter being a default (to determine what to return of no value is found).


Same with get.

Lucy Wang00:10:41

I guess you mean ->>, not -->


there are plenty in all code i've worked with


not sure if you mean something else by continuous


it can definitely be overdone


it's like juxt, once someone discovers it, they gotta get their money's worth and use it everywhere

😂 4

@gleiry.serrano do you have examples?


I am looking for this tutorial


Usage of threading macros here looks reasonable and idiomatic to me (but I'm a beginner myself). @ghadi what do you think?


it's ok yeah


I wouldn't do the once with the cons


refactoring tools should allow instant switching between unrolled and threads, see how you like it. clj-refactor in emacs, e.g.


nice. good to know your opinion. I was thinking that in some cases it would be actually more clear if you just wrap the functions. I find it confusing when there are multiple arguments to functions.


There’s that company called Juxt even. When is someone going to start a company called ->?

😄 8

AMZ already did?!


I am wondering if there is a way to get the source location of the definition of a symbol, similar to clojure.repl/source and clojure.repl/source-fn?

Alex Miller (Clojure team)15:10:00

the var meta has location attributes

user=> (-> `map resolve meta (select-keys [:file :line :column]))
{:file "clojure/core.clj", :line 2727, :column 1}

💯 8
Alex Miller (Clojure team)16:10:40

which is actually how source works - by finding the location and reading the code out of the file


@U064X3EF3 Is there also a way to get this kind of information locally. So if I have: `


(let [x 1]
  (letfn [(id [x] x)]
    (id x)))


I would essentially like to know that x on line 3 refers to line 1 and id on line 3 refers to line 2.


If I want to do this in general for clojure code it seems that one needs to write an interpreter that keeps track of source locations. Or is there a better way?

Alex Miller (Clojure team)14:10:38

well, most people use tools.analyzer to answer those kinds of questions

Alex Miller (Clojure team)14:10:58

you're basically doing the same job as the compiler so that's the kind of tool you need


symbols aren't defined, only vars are defined


@ghadi Sorry coming from Common Lisp not used to that yet, vars then.

Zac Bir15:10:35

Hey, all. Trying to figure out the idiomatic (functional (i.e. one return)) way of doing this kind of approach:

for c in circles - {circle}:
            if < (circle.size + c.size):
                return False
        return True
I’ve looked at this answer (, and I’m not exactly reducing the set, just iteratively comparing an element to a reference. What’s the right approach to make this fail faster if it finds an overlap early on?


@finn.volkel most people use jump-to-definition in their editor


(every? (partial far-away? center-circle) other-circles)

💯 8
Zac Bir15:10:44


Alex Miller (Clojure team)15:10:00

the var meta has location attributes

user=> (-> `map resolve meta (select-keys [:file :line :column]))
{:file "clojure/core.clj", :line 2727, :column 1}

💯 8
Mario C.16:10:04

What does a - signify in a function name?

Mario C.16:10:29

(-uninitialized [this] (->AttCalc nil nil nil)) for example

Mario C.16:10:07

I know its a protocol definition but is that what the dash means? A convention for protocol names?


@mario.cordova.862 It is nothing more than a convention for protocol method names (I believe initiated when the ClojureScript compiler was first being developed) that helps avoid collisions with "regular function" names that don't have such a prefix. For example, there is cljs.core/-assoc which is specified by the cljs.core/IAssociative protocol, and which is distinct from cljs.core/assoc


it often means something like "don't call this directly, instead call the function function without the '-' which may eventually bottom out at using this protocol function"


very similar to how sometimes the suffix '*' is used


but the suffix '*' is more common for regular functions while the prefix '-' is more common for protocol functions


This very topic arose in Clojure Inside Out and Stu provided an answer. I’ll dig it up...


In Clojure Inside Out, video 7 on Abstraction, Stu’s explanation was along these lines - hyphen is a legal naming character - to avoid naming collisions, this became idiomatic in ClojureScript - this was not idiomatic when Clojure was created and thus is not done there - This is just a convention; no actual language semantics

Mario C.16:10:12

Okay that makes sense, thanks

Lucas Barbosa20:10:35

Is ClojureScript - Up and Running from 2013 still a good place to learn cljs?


That sound too old to be useful as a beginner


Can someone explain what the $ operator means in this example from the docs? (as-> owners $ (nth $ 0) (:pets $) (deref $) ($ 1) ($ :type))


$ is just an arbitrary name


clojure doesn't have very many operators, I think most of them have . in them


=> (doc as->)
([expr name & forms])
  Binds name to expr, evaluates the first form in the lexical context
  of that binding, then binds name to that result, repeating for each
  successive form, returning the result of the last form.


so you could change every $ to x and the code would mean the same thing


user=> (macroexpand '(as-> owners $ (nth $ 0) (:pets $) (deref $) ($ 1) ($ :type)))
(let* [$ owners $ (nth $ 0) $ (:pets $) $ (deref $) $ ($ 1)] ($ :type))


Hm, interesting. Thanks.


So in the case of as-> it’s just acting as a placeholder for that parameter in the list?


it's updated at each step and is always the result of the previous step


it's more of a series of invisible rebindings than a placeholder


breaking it down with small simple steps might help

user=> (as-> 0 x (inc x))
user=> (as-> 0 x (inc x) (+ x x))


the original example can be rewritten as (-> owners (nth 0) (:pets) (deref) (get 1) (:type))


the usage of the threaded value as the function is odd enough in this context I assume it was done for the sake of an example