Fork me on GitHub
#clojure
<
2018-03-22
>
Alex Miller (Clojure team)02:03:41

they definitely share some goals

JJ03:03:04

What's the correct syntax to pass --add-modules java.xml.bind to 'clj' ?

JJ03:03:43

clj -O:--add-modules -O:java.xml.bind

seancorfield03:03:41

@devicesfor -O is for aliases in your deps.edn. You want the -J option to pass JVM options on the command line.

seancorfield03:03:29

clj -J"--add-modules java.xml.bind"
is probably what you want

seancorfield03:03:06

Hmm, no... spaces are problematic...

seancorfield03:03:46

clj -J--add-modules --Jjava.xml.bind
might work (I don't have Java 9 locally so I can't test that)

JJ03:03:28

thanks, was close

JJ03:03:48

couldn't find the -J way so was trying with -O 😜

JJ03:03:11

@seancorfield so -O is to activate jvm options that are in deps.edn ?

JJ04:03:16

yean, nvm

seancorfield04:03:29

clj --help
is your friend 🙂

seancorfield04:03:18

-O is an alias selector, so if you have {:aliases {:foo {:jvm-opts [...]}}} then -O:foo will bring in those JVM options...

JJ04:03:00

you know how do I see the complete stack trace at the repl ? I'm doing (.printStackTrace *e) but I get '... 43 more' at the end

seancorfield04:03:40

Just *e should show the whole thing as data?

seancorfield04:03:22

Or maybe look at the clojure.stacktrace namespace?

qqq05:03:48

do *.cljc files have file size limits? I'm doing something of the form (def my-static-data (read-at-compile-time "some-file")) where read-at-compile-time is a macro that reads at compile time

xtreak2905:03:58

I am trying to design an API wrapper for a Java library . There are many functions like draw-rectangle, draw-circle in the Java lib with different parameters for my clojure library to wrap around. Should I use multimethods with :type and take in a large map or make separate functions like draw-circle, draw-rectangle and so on? Is there a guide or any other repos I can look for API design inspiration like Python requests?

kardan06:03:22

@xtreak29 Another solution would be to use a protocol like IRender.. (render [shape] …) and have a render function that is full filled by different implementations for rectangle & circles. But then it depends on what you want to do with you API wrapper. Be true to the Java lib and not introduce indirections to the lib user or present a “clean” API for the Clojure developer with more things behind the curtain. Not sure I have a suggestion of a reference implementation.

mv07:03:38

I’m trying to build a web app in vase/pedestal, getting a little stuck on user authentication/authorization. Is there an example of a pedestal app that handles user auth? If not, what’s the best currently library for user auth in web apps?

xtreak2907:03:27

There is an example in the friend-sample branch but it's around 5 years old : https://github.com/pedestal/samples/blob/friend-sample/friend-auth/src/friend_auth/service.clj Friend and buddy are the recommended ways to do auth in Clojure Friend : https://github.com/cemerick/friend, https://github.com/cemerick/friend-demo Buddy : https://github.com/funcool/buddy-auth

sarna09:03:38

do I have to release all my Clojure code under the Eclipse Public License? can't I do it under, let's say, MIT?

xtreak2909:03:06

You can choose any license AFAIK. I have my projects released under MIT and know many popular ones that use MIT

xtreak2909:03:41

TIL, Thanks for the links :thumbsup: . Ring is a very popular library and it's MIT licensed : https://github.com/ring-clojure/ring/blob/master/LICENSE

👍 4
ajs10:03:22

is there a way to turn off all the output that is sent to nrepl? Every message i get over a websocket is going there, and I wonder if all that logging is creating some big latency I'm seeing. I'd like to turn off what nrepl prints

danielcompton11:03:47

Is there any way to get the depth of the tree when using clojure.walk/postwalk?

danielcompton11:03:56

or a similar tree walking function

danielcompton11:03:10

depth inside a zipper would also work

pesterhazy11:03:56

The implementation of postwalk is pretty short, you could copy 'n paste that and add the depth as a argument to the walker fn: https://github.com/clojure/clojure/blob/master/src/clj/clojure/walk.clj#L58

sundarj11:03:22

what about tree-seq?

danielcompton11:03:08

(defn depth
  "Calculate how far we are inside the zipper, by ascending straight up
  until we can't get any higher."
  ;;  There is probably a smarter way to do
  ;; this than checking for nil, but I'm not sure what it is.
  [loc]
  (loop [loc loc
         depth -1]
    (if (nil? loc)
      depth
      (recur (z/up loc) (inc depth)))))

danielcompton11:03:43

zippers are ideally what I'd work with, but I like your idea too @pesterhazy

danielcompton11:03:45

@pesterhazy might be a lack of imagination on my part, but how would you get hold of the depth there?

pesterhazy11:03:36

@danielcompton hm not sure. The clojurew.walk code is very compact...

renewdoit12:03:47

clojure.spec.test.alpha/check sometimes very slow, 30 tests take almost forever while 10 tests run very fast. I bind recursion-limit to 1 while still not helping.

danielcompton12:03:26

@renewdoit can you share an example?

renewdoit12:03:16

@danielcompton it contains lots of multi-spec and has recursive structure

renewdoit12:03:39

@danielcompton it is slow when in cider, and runs fine in console, maybe I should check the cider environment.

borkdude12:03:45

I googled for this error message clojure.lang.ExceptionInfo [m: reader-error does not exist [m but I can’t find anything useful.

ajs13:03:34

If I create a file resources/jetty-logging.properties in my project directory, and ensure that project.clj has this line: :resource-paths ["resources"] (I also tried with the trailing slash, :resource-paths ["resources/"]), then when I restart the repl/CIDER, that properties file should be read by JVM, right?

Matt Grimm15:03:41

Where does the "lazy" in LazilyPersistentVector come from? It always returns an instance of PersistentVector, and I was under the impression vectors were non-lazy.

tomaas15:03:08

hi, is this some config stuff or it is not possible to lein uberjar code that has (defn b [] (a)) (defn a [] 1) defined in this order?

pesterhazy15:03:40

you need to (declare a) before using it

pesterhazy15:03:51

nothing to do with uberjar — same in the repl

tomaas15:03:13

ok, thanks

tomaas15:03:40

yeah in the repl the old stuff is already evalued when i added some new function

pesterhazy15:03:53

right, that's a common gotcha

tomaas15:03:11

would be nice if compiler was smart enough to do this

pesterhazy15:03:56

I like that about clojure actually. Also makes the compiler fast

tomaas15:03:35

yes actually it's better, everything is logically ordered this way

tomaas15:03:11

@pesterhazy do you then use something like jslint or whatever to at least let the editor catch these kind of things?

borkdude15:03:15

sooo, does Java 10 speed up a clj script even more? haven’t tested it yet

borkdude15:03:08

💯 on joker!

tomaas15:03:52

thank you, let's see

ghadi16:03:41

Is there a Windows room here? I have some s

jumar16:03:19

This is a fantastic reading: https://gist.github.com/jumarko/d672dbe746b3c10ee2690b2e17624de3 There are probably many things that I don't understand, but to mention one: > protocols support direct implementation composition, which, in my opinion, is far preferable to inheritance I'm not sure what exactly "protocols support directly implementation composition" really means here. Can anyone elaborate on that a bit more?

👍 4
val_waeselynck17:03:21

Wow, it *is* a fantastic reading 😮

andy.fingerhut21:03:44

Looks like a good thing to add to this repository: https://github.com/matthiasn/talk-transcripts -- I can do that if you do not mind (happy to attribute who ever typed in the transcript, if you know who that was)

👍 8
jumar08:03:19

@U0CMVHBL2 that would be great. I don't really know who did that. I've found the original gist on Google: https://gist.github.com/harfangk/f98e627f7567b7b5741fe0c239b57d6c

tbaldridge16:03:48

@jumar it means that given a protocol IFoo you can extend it to any type, new or previously existing. Unlike interfaces which require you to inherit from the interface at compile time. So assume I have ICounted as a protocol, I can just easily add it to a new type as I can to go and do this

(extend-protocol ICounted
  String
  (count [this]
    (.getLength this)))

👍 4
tbaldridge16:03:47

String is a built-in type that I can't modify, but protocols allow me to extend the protocol to this type. This really helps with things like the "expression problem"

jumar16:03:50

Ah, okay, so the "composition" here means adding new capability to the existing data type. I was thinking about extend-protocol as related to the first Rich's claim, that is "Protocols support direct connections of datatypes to protocols, without any inheritance" and was somewhat puzzled by the "implementation composition" words.

emccue16:03:24

what would the idiomatic way to use a library like vavr?

emccue16:03:50

For example, I have a few methods in a java library that return Try<JSONObject>

the2bears16:03:21

@tomaas Rich Hickey gives a nice explanation here, regarding single pass compilation and the nature of compilation units: https://news.ycombinator.com/item?id=2467809

JJ16:03:00

is there public history for this channel somewhere?

emccue16:03:31

(my thing is also blocked by https://dev.clojure.org/jira/browse/CLJ-2284, but thats neither here nor there)

seancorfield16:03:36

@devicesfor The log display site is/was broken and not showing anything past November last year -- the logbot is working so messages are still being archived, and there's a new website coming to display those archives.

JJ16:03:05

@seancorfield what log display site are you referring to?

seancorfield17:03:58

@devicesfor The one Matt Grimm linked you to.

seancorfield17:03:49

Ah, looks like Arne has already got the updated app up and running there now!

JJ17:03:42

I don't think they are complete 😉

emccue17:03:20

@schmee Its a good start regardless

borkdude17:03:49

I wish there was a way to make this work without macros

(def expected-keys [:title :content
                   :id :icon :widget-class :init-collapsed?
                   :configuration :dropdown :controls :tabs :collapse-opts
                   :help])

(let [{:keys expected-keys opts] ...)

borkdude17:03:54

so have the keys in a tangible data structure that you can pass around and being able to destructure on it

seancorfield17:03:34

@devicesfor Only channels where @logbot has been invited in get logged -- and the latest messages are from earlier today, as far as I can see.

seancorfield17:03:23

@borkdude You can do the reverse tho' -- given a keys spec, you can call s/form on it and parse out the keys.

seancorfield17:03:40

That way the spec is the "system of record" and you can derive all sorts of things from it.

borkdude17:03:55

ooh, I’ll look that up

borkdude17:03:43

no mention of form in the guide

seancorfield17:03:52

It's what we do at work -- we have specs for several entities (that relate to tables in our database) and we derive the set of keys from those specs so that we can ensure we don't try to insert columns that don't exist.

borkdude17:03:53

returns the spec as data… ok…

borkdude17:03:32

What I need is to destructure on the keys so I have them as variables

seancorfield17:03:23

user=> (s/def ::table (s/keys :req [::id ::name ::description]))
:user/table
user=> (s/form ::table)
(clojure.spec.alpha/keys :req [:user/id :user/name :user/description])
user=> (let [[_ & {:keys [req]}] (s/form ::table)] req)
[:user/id :user/name :user/description]
user=> 

👌 4
seancorfield17:03:57

Ah, and then you want to use that list of keys in a destructuring expression?

seancorfield17:03:04

@borkdude Some macro magic:

user=> (s/def ::table (s/keys :req [::id ::name ::description]))
:user/table
user=> (s/form ::table)
(clojure.spec.alpha/keys :req [:user/id :user/name :user/description])
user=> (let [[_ & {:keys [req]}] (s/form ::table)] `(let [{:keys ~req} {::id 1 ::name "borkdude" ::description "Someone who wants to destructure spec keys"}] (println ~'id ~'name ~'description)))
(clojure.core/let [{:keys [:user/id :user/name :user/description]} #:user{:description "Someone who wants to destructure spec keys", :name "borkdude", :id 1}] (clojure.core/println id name description))
user=> (eval *1)
1 borkdude Someone who wants to destructure spec keys
nil
user=> 

seancorfield17:03:55

refactor that into a macro and you should be good to go! 🙂

ddellacosta20:03:53

so, the lazy-seq docstring says > Takes a body of expressions that returns an ISeq or nil but it seems like it is working with any collection-producing code I’m throwing at it--what am I missing here? Reading the code was not super illuminating, it looks like maybe it’s wrapping the passed-in forms up in an anonymous function call, although I’m a bit fuzzy on how to parse it with all the syntax quoting: https://github.com/clojure/clojure/blob/841fa60b41bc74367fb16ec65d025ea5bde7a617/src/clj/clojure/core.clj#L675

ghadi20:03:13

you can give it anything that you can call seq on, like a vector. Internally LazySeq will call seq.

ddellacosta20:03:59

okay, so the docstring is wrong, or am I misunderstanding what the docstring is saying?

ghadi20:03:13

docstring seems right to me

ghadi20:03:04

if you give it (blah), it will take your (blah) and wrap it in a "thunk" (fn [] (blah)) then call the LazySeq constructor on it (LazySeq. (fn [] (blah)))

ghadi20:03:58

Now the first time something calls seq on this lazy-seq (usually indirectly, like map), internally LazySeq will invoke the thunk, then call RT.seq() on the result of that

ddellacosta20:03:16

okay, that much makes sense, and is roughly what I was assuming

ddellacosta20:03:31

but it’s not explaining the bit of the docstring I highlighted

ghadi20:03:32

(blah) needs to return either something seqable or nil

ghadi20:03:18

so yeah the docstring is not exact, but conveys the idea

ddellacosta20:03:13

okay, that’s not super satisfying, but I’m probably not explaining my confusion well enough. Let me try a repl code example:

ddellacosta20:03:18

user=> (doc seq?)
-------------------------
clojure.core/seq?
([x])
  Return true if x implements ISeq
nil
user=> (seq? (reduce #(conj %1 %2) [] [1,2,3]))
false
user=> (lazy-seq (reduce #(conj %1 %2) [] [1,2,3]))
(1 2 3)
user=>

ddellacosta20:03:38

again, that chunk of docstring that is confusing me: > Takes a body of expressions that returns an ISeq or nil

ddellacosta20:03:53

what am I thinking about incorrectly here?

ghadi20:03:06

user=> (seq? [:a :b])
false
user=> (seq? (seq [:a :b]))
true

ddellacosta20:03:18

okay, so, the docstring is wrong?

ghadi20:03:28

it's not wrong, it's just not fully comprehensive

ddellacosta20:03:45

in what sense am I returning an ISeq in my reduce example?

ddellacosta20:03:14

or even, “a body of expressions that returns an ISeq?” if that distinction matters

ghadi20:03:54

Maybe I've got stockholm syndrome. How could we improve it?

ddellacosta20:03:27

I’m not sure, because all I am now is thoroughly confused--I’m not sure what you’re trying to say, and I’m not sure what the docstring is telling me either. I suspect--I hope!--there is something wrong with my understanding, but nothing you’ve stated so far is pointing out what it is exactly that I’m confused or wrong about, as far as I have been able to tell.

ddellacosta20:03:32

I appreciate you trying, don’t get me wrong.

ghadi20:03:47

A sloppier doc would say, "Takes a body of expressions that can produce a seq or nil"

ghadi20:03:56

A vector can produce a seq, etc.

ghadi20:03:08

without being a seq

ddellacosta20:03:20

a vector is just data, how does it produce a seq?

ddellacosta20:03:35

and all of that aside, why does my reduce example work?

ddellacosta20:03:52

I don’t see how seq is involved there, in terms of the code I’m passing in

john20:03:17

A sequence is an abstraction which many of our functions call into. Many collections implement the seq interface. You can implement a function that works on a seq and if it is given a collection that implements that interface, it'll be able to operate over it.

ddellacosta20:03:48

wow, this is a lot of talking past each other

ddellacosta20:03:44

I’m not sure how I could be more clear than the code example I posted above, but let me know if there’s something else I could provide to make it clear what I’m confused by. Thanks everyone for trying to help, I appreciate it nonetheless

john20:03:11

a seqable collection can sort of be turned into a seq, by calling seq on it, such that afterward, calling seq? on it becomes true.

ddellacosta20:03:34

SO the docstring is in fact--let’s be gentle here--imprecise

john20:03:42

lazy-seq is calling seq on the seqable collection

dpsutton20:03:59

> Takes a body of expressions that returns an ISeq or nil

john20:03:23

The collections can return a seq`able thing

dpsutton20:03:33

so this is not a comprehensive description of the forms acceptable to lazy-seq

john20:03:33

Words aren't easy though

dpsutton20:03:43

his original question was if the docstring could be wrong

dpsutton20:03:55

and it appears yes. the docstring is not faithful to what lazy-seq can operate on

dpsutton20:03:11

unless this is "undefined behavior" that happens to work now

dpsutton20:03:06

i don't think this was an attack on the docstring. everyone knows words are hard and the seq sequence stuff gets complicated. this was just "is there more here?"

ddellacosta20:03:07

okay, that was all I wanted to know, thanks @dpsutton

👍 4
ddellacosta20:03:05

I think it could be easily improved by defining the exact types it takes and returns

ddellacosta20:03:19

(now that I know what the problem is)

john20:03:31

(seqable? (reduce #(conj %1 %2) [] [1,2,3])) ;=> true

ddellacosta20:03:14

huh, can’t find that function

ghadi20:03:16

> "Takes a body of expressions that can produce a seq or nil" You're not going to want to enumerate all the specific types

ddellacosta20:03:44

I mean, I would, I guess I’m in the minority here though

dpsutton20:03:46

maybe using a specific interface then is inappropriate if we can't enumerate them all?

ddellacosta20:03:56

whoops, just realized I read this backwards, sorry if my response didn’t make sense

ddellacosta20:03:57

that would be nice. Something like…`ISeq` 😂

dpsutton20:03:59

sequable might be more meaningful than a specific term ISeq which is wrong?

ddellacosta20:03:27

I dunno, this is my usual Clojure experience frankly so I’ll stop there…I recognize I’ve got a different perspective than most Clojure devs

ddellacosta20:03:47

anyways, thanks again for the help, sorry for any confusion I caused

markw20:03:05

"Lazy sequences can be created with the lazy-seq macro, which takes a body that yields a seq, nil, or anything seqable."

markw20:03:24

"anything seqable" is the missing piece I think

markw20:03:59

although a vector doesn't implement ISeq itself, it is still "seqable" because you can call seq on it and get back a seq

john20:03:32

@ddellacosta I find the point you're bringing up to be quite interesting actually

john20:03:07

Well, a lot of us have a bias. And when someone comes in with new-comer complaints, some are valid and some aren't. Like @ghadi said, we may have stockholm syndrome. I just find it interesting what kinds of improvements might be shadowed by our biases, etc.

ddellacosta20:03:42

FWIW I’ve been writing Clojure professionally since, I think it was 2013 when I got my first Clojure job? I forget

john20:03:45

well, not to say you're a new comer

john20:03:57

I think I recall your name around

john20:03:18

but your frustration was one that we've all felt at a certain point, when dealing with seqs

ddellacosta20:03:22

I mean, that’s beside the point I think

ghadi20:03:23

Generally in the core library, anything that can take a seq can also take things that you can coerce to a seq

ddellacosta20:03:25

yeah I mean, to be clear I was trying to dig into what exactly the docstring was trying to tell me. It gave a pretty precise definition but it was not one that seemed consistent with how the function was behaving

ddellacosta20:03:31

that’s all I was getting at

Alex Miller (Clojure team)20:03:44

sorry, joining this late and didn’t read all the backchat. I would actually say that sequence functions in the core library generally take seqables (and seqs are a degenerate seqable)

ddellacosta20:03:47

I think @markw’s comment above was helpful

ddellacosta20:03:03

@alexmiller thanks, yeah, makes sense

Alex Miller (Clojure team)20:03:18

generally the sequence functions should also be considered to also return something seqable (not a seq)

Alex Miller (Clojure team)20:03:58

it’s obscure why this is, but effectively there are some cases where we can avoid forcing a seq that way which actually makes a difference from a performance perspective

Alex Miller (Clojure team)20:03:41

also note that seqable? was just added in Clojure 1.9

ddellacosta20:03:07

ah, yeah, my current repl is 1.8

ddellacosta20:03:14

that sounds like an important and useful function to have

ddellacosta20:03:42

also, @alexmiller it doesn’t seem like seqable is defined precisely anywhere on the main doc site--is this deliberate?

Alex Miller (Clojure team)20:03:08

I don’t think so, more likely just reflects evolving thinking about the nuances of this stuff over time and docs not keeping up

ddellacosta20:03:26

gotcha. That’s also helpful, thanks

Alex Miller (Clojure team)20:03:14

it was added to make spec’ing sequence functions practical :)

djtango20:03:30

Hey all, is this behaviour expected for clojure.test? I would have expected thrown? to realise lazy results

(testing (is (thrown? AssertionError (assert (= 1 0)))))
;; 0 failures, 0 errors.
(testing (is (thrown? AssertionError (map #(assert (= % 0)) [1]))))
;; FAIL 
;; expected: (thrown? AssertionError (assert (map (fn* [p1__21975#] (= p1__21975# 0)) [1])))
;; actual: nil
(testing (is (thrown? AssertionError (doall (map #(assert (= % 0)) [1])))))
;; 0 failures, 0 errors.
(testing (is (thrown? AssertionError (mapv #(assert (= % 0)) [1]))))
;; 0 failures, 0 errors.

djtango20:03:25

Looking at the source for thrown? is it because the body is evaluated and so if the result itself is lazy, nothing will realise it?

noisesmith21:03:48

right, evaluating a lazy form doesn't force any of its elements, you need to do something that actually accesses things inside it

markw21:03:15

I like that I can post an article from 3 years ago, and the author shows up 3 min later to clear everything up

markw21:03:54

he sees the batlight and then poof... there he is

johnj21:03:35

when a library specifies a dependency in its project.clj/deps.edn etc.. , does that implies the library must use that exact version or implies it is the minimum version required?

hiredman21:03:08

it implies that it was tested against that version, and doesn't imply anything about other versions

johnj21:03:13

ok, that implies the version specified is the safest version then 😉

johnj21:03:03

@hiredman but what if you need to use a newer version of that transitive dependency? is this the famous jar hell problem?

Michael Fiano21:03:16

You can also use "LATEST" I figured out recently, though I'm just a Maven newbie

danielcompton23:03:51

Does anyone know what :forms means in the context of var metadata? It looks like it serves the same purpose as :arglists, but I think there must be something else as well

danielcompton23:03:31

defn uses :arglists but fn uses :forms

hiredman23:03:44

:forms is a special thing the doc function uses for example forms

hiredman23:03:05

it is not the same thing as arglists