#clojure log - Nov 03 2015

The Joy of Clojure
Main Clojure site
Google Group
List of all logged dates

2:37 jeaye: How can I explode the result of a function call to the remaining arguments of another?

2:38 (wants-three 1 (explode (gives-two)))

2:39 Pulling it out into a let would be my first move, I just wonder if there's a library macro for this.

2:41 opqdonut: apply?

2:41 jeaye: Yup.

2:41 opqdonut: ,(apply + 1 (concat [2 3] [4 5]))

2:41 jeaye: Just had found that apply can do it.

2:41 clojurebot: 15

2:42 jeaye: Thanks.

2:48 What's a good way of organizing helper functions in a namespace? foo.core has some helpers, foo.bar has some of its own, etc.

2:49 In C++, it's common to have a `detail` or `impl` namespace per each namespace that has helpers.

2:59 jonathanj: is there a convenient way to do: (f (.foo o) (.bar o) (.baz o))?

3:00 since .foo is a reader macro (or something?) ((juxt .foo .bar .baz) o) won't work

3:48 TEttinger: jonathanj: there is memfn for turning java methods into fns

3:49 (doc memfn)

3:49 clojurebot: "([name & args]); Expands into code that creates a fn that expects to be passed an object and any args and calls the named instance method on the object passing the args. Use when you want to treat a Java method as a first-class fn. name may be type-hinted with the method receiver's type in order to avoid reflective calls."

3:49 tdammers: oh wow that looks super useful

3:53 jonathanj: that's useful, just not really so much here

3:55 tdammers: it kind of is, indirectly

3:55 you can use memfn to wrap those methods, and then you can thread or compose them

3:56 memfn creates actual clojure fns, so unlike the sugared java method calls, you can use those in threading macros without further ado

4:45 cfleming: I'm having a problem with lazy seqs and mutually recursive functions.

4:45 I read on SO a post by amalloy saying that they were fundamentally incompatible, but I don't understand why.

4:46 I have some code which looks like it should be ok, but blows the stack immediately, with what looks like an infinite loop.

4:46 There isn't enough data for it to be the problem from Stuart Sierra's concat post.

4:48 Fender: do you have a link to the source code?

4:48 cfleming: I can refheap it, one sec

4:51 Fender: https://www.refheap.com/111314

4:52 It's basically a simple top-down parser for a simplified EDN, which should output a lazy sequence of formatting primitives (the {:op...} maps)

4:54 The issue appears to be in map-entry, which uses lazy-cat to recursively generate the ops for a series of map entries

4:54 Fender: I don't fully understand what's going on in the top part but a nice way to get an SO over there would be to have #(expression lexer) always return something non-nil

4:55 you could rule that out by putting some (take 1000) in between

4:55 cfleming: Yeah, it's additionally tricky because the lexer is mutable

4:56 I'll try just taking one element from the lexer instead of iterating at line 48

4:57 Fender: yes, you'll probably see by what the lexer generates where it's stuck

4:57 obviously peek is supposed to consume something in the mutable state there

4:57 cfleming: No, if I replace lines 48-50 with just (expression lexer) it still barfs, it's something in the mutually recursive functions.

4:58 No, (peek) doesn't consume - (token) does.

5:00 Fender: is the stacktrace clear as to where it repeats?

5:00 alternatively you could println something at the entry of each fn

5:01 additionally, can you make sure that (token) consumes something? because idiomatically it could also be written as (token!)

5:01 cfleming: Yeah, I'm thinking that's what I'll have to do. The loop is RT.seq -> LazySeq.seq -> LazySeq.sval -> concat/cat/fn

5:02 Fender: from my limited understanding I suppose lazyseqs shouldnt be the problem because in the worst case you'd just traverse it all

5:02 well, that is ...

5:02 I think you don't know the mutable state when the lazy-seq is executed

5:03 IOW, you don't know when each lazy-seq is realized

5:05 so when it's realized it's calling the lexer but it might be that this is not in order

5:06 so if you have a lazy-seq and you first realize elements 0 and 1 and then deep dive into 0->0 then there could be a problem

5:07 in get-in syntax this would mean (get-in x [0]) (get-in x [1]) (get-in x [0 0]) would not be the intended order of traversal in a depth-first traversal because [1] should come after [0 0]

5:08 cfleming: I'm pretty sure in this case that the element should always be traversed in order

5:10 Oh, I see the problem

5:10 I'm not correctly checking for the case where the lexer has no more entries

5:11 It's nothing to do with laziness or anything, just a common or garden bug :)

5:11 Fender: haha

5:12 let me guess, the when-let always returns something because of the vector decomposition?

5:12 (line 9?)

5:13 luma: no, when-let checks the value of the expression (token lexer), and if that is truthy, destructures that into [type text]

5:13 cfleming: No, in that case when-let... right

5:14 I'm not quite sure how it's happening, but map-entry is somehow getting called when the lexer has no more elements, which it shouldn't. It doesn't check for that case, because it shouldn't have to - it should always get a closing }

5:16 Fender: I stand corrected

5:18 ok, well how about: map-entry is calling itself and collection-element as well

5:18 that's probably what you mean

5:20 anyone here knows how to reference a simple clj file with just definitions from cljs?

5:21 the clj file just contains def'ed code and no dependencies

5:21 and all of it without side effects

5:32 kungi: Programming: Solving problems yourself you created yourself ... :-|

5:45 cfleming: Fender: So this is a little embarrassing: (= ClojureTokenTypes/LEFT_CURLY)

5:45 (always true)

5:46 Fender: haha ok^^

5:46 cfleming: Ironically I'm actually doing this as part of prep for my conj talk, where I will be talking about how to fix just this sort of error :)

5:47 s/fix/get warned about/

5:50 Fender: like in the old days when the compiler writing guys would have been happy to have a compiler that they could use

7:28 Glenjamin: does anyone know a good way to find out what has started an agent? My uberjar compilation is hanging while the agent pool closes

8:37 jeaye: Is there something like update-in which just accesses nested elements based on a "path" of indices?

8:37 filben: get-in?

8:37 jeaye: muahaha

8:37 Makes sense; thanks.

8:37 filben: np

8:39 puredanger: Glenjamin: you can build a hacked version of Clojure that dumps stack at the point where an action is dispatched

8:40 Glenjamin: :'(

8:40 i suppose maybe i could alter-var-root something if i get it in early

8:43 noncom: Glenjamin: also you could avoid building and just redefine things inside the core

8:43 although, i heard, it may be impossible with clojure 1.8+

8:52 puredanger: The th no you can't do in 1.8 is with-redefs of something in core and have other things in core see it

8:56 But it's worth a try - the main things that dispatch are future and send

8:57 gfredericks: Glenjamin: user.clj is a good trick for alter-var-rooting things early

9:08 visof: hi guys

9:12 assume i have list of methods like this (foo bar xxx yyy) and want to apply on something as (yyy (xxx (bar (foo something)))) but method's list has undetermined number of rules, what is the best way to do this (apply comp list-methods something) ?

9:12 this is the right way to do this?

9:13 oddcully: what do you mean by "number of rules"?

9:14 visof: number of methods

9:15 (foo bar xxx yyy) contain 4 methods, maybe 3 or whatever n methods in the list

9:15 oddcully: well apply comp does not look bad?

9:15 ,((apply comp [inc inc dec]) 5)

9:15 clojurebot: 6

9:16 visof: oddcully: ok

9:19 oddcully: but dec is applied first right?

9:19 gfredericks: yep

9:19 visof: (inc (inc (dec 5)))

9:20 ah okay

9:20 so i need to reverse before apply if i want to apply from the beginning of the list

9:22 oddcully: ,(reduce #(%2 %1) 5 [inc inc dec])

9:22 clojurebot: 6

9:50 phaseNi: ,(-> 5 inc inc dec)

9:50 clojurebot: 6

9:50 phaseNi: :P

9:56 justin_smith: ,(-> 5 / / /)

9:56 clojurebot: 1/5

9:56 justin_smith: ,(-> 5 / / / /)

9:56 clojurebot: 5N

9:56 oddcully: ,(defmacro apply-rules [init fns] `(-> ~init ~@fns))

9:56 clojurebot: #'sandbox/apply-rules

9:56 oddcully: ,(apply-rules 5 [inc str seq])

9:56 clojurebot: (\6)

9:58 timvisher: is anyone aware of a `safe-min` implementation somewhere in the standard libraries. something like `(defn safe-nil [&args] (->> args (remove nil?) seq (apply min))`?

9:59 justin_smith: no, but I'd do it as (reduce (fn [i n] (if (and n (< n i)) n i)) coll)

9:59 timvisher: justin_smith: 👍

10:00 justin_smith: timvisher: that symbol doesn't work in my irc client :(

10:01 haha, just found it in the log, same to you buddy :)

10:01 ( http://clojure-log.n01se.net/ for those curious)

10:02 timvisher: justin_smith: ah. y u no emoji? :)

10:02 gfredericks: justin_smith: doesn't work for me in my client *or* my browser

10:02 timvisher: i don't have ascii art for thumbsup

10:02 justin_smith: timvisher: tty client running on a virtual ocean droplet - I guess it might be misconfigured?

10:02 gfredericks: it's a thumbs up

10:03 timvisher: justin_smith: mmm. i'm running in a tty session in erc in emacs and it displays for me. but i have fonts set up that can handle it. ¯\_(ツ)_/¯

10:03 i wonder what that looks like? :)

10:04 gfredericks: that one looks fine

10:04 justin_smith: timvisher: yeah, it's somewhere between the terminal I am running natively, the tty settings on my vhost, and the settings on my irc client - I'm getting "unknown unicode" directly as a symbol - I assume the client does that?

10:05 timvisher: with broken unicode I expect to at least get some gibberish I can paste into another window and figure out what it really was

10:05 timvisher: justin_smith: i'd guess so. i think the character codes are still present so i'd expect that as well

10:06 justin_smith: I might just switch from this irc client to emacs running just so it can run erc

10:06 hah

10:06 at least I could trust it to handle weird characters

10:06 (even if the font is wrong, it will at least tell you the *name* of the character)

10:06 timvisher: justin_smith: i have a dedicated emacs instance running with just erc that i mosh to to irc :)

10:07 justin_smith: I might be joining that club

10:07 timvisher: i think i picked that up from technomancy

10:07 justin_smith: is mosh that much better than ssh + screen?

10:08 timvisher: justin_smith: mosh + (screen|tmux) is _so_ much better than ssh + (screen|tmux)

10:09 gfredericks: I've stopped using tmux and just use an emacs server now

10:10 justin_smith: that makes sense - emacsclient in a tty is cool

10:10 and who am I kidding - I don't need to do anything on this host I can't do inside an emacs window

10:11 gfredericks: yeah who are you kidding

10:11 it even works better than tmux for having multiple computers logged in

10:11 with tmux I always had to detach everything else so that I wouldn't get sizing constraints

10:12 justin_smith: with screen I learned to love "C-a F"

10:12 (force size to size of current screen)

10:12 gfredericks: I can't even remember anything about screen

10:12 justin_smith: ha

10:12 gfredericks: but I've learned I can use screen inside an emacs term buffer :)

10:13 tdammers: screen inside screen is where it gets weird

10:13 justin_smith: gfredericks: to me, tmux is that program I need to know how to use because I have projects where people think running lein run inside a tmux session is an OK way to run a server

10:13 tdammers: C-aC-a - easy!

10:13 gfredericks: justin_smith: I must be reverse of you; my team does a lot of prod stuff w/ screen

10:14 tdammers: justin_smith: simple vs. easy, huh

10:14 justin_smith: gfredericks: ugh, really everybody, use uberjars and nohup, or better yet, stop using printlns for logs and use a file appender

10:14 timvisher: justin_smith, gfredericks: i've been unable to get anything like the kind of isolation i'm used to with multiple emacs instances inside many tmux sessions in a single emacs server instance.

10:14 Schrostfutz: I'm doing a course on clojure and they introduce head recursion on the example of element count or frequencies, where they pass the count/frequencies to each recursive call. Is there a advantage of doing that instead of tailrecursion which should work there, too?

10:14 timvisher: everything that tries to solve that problem is an ugly hack compared to just running multiple instances.

10:16 tdammers: Schrostfutz: the problem with head recursion is that it leaks stack space; tail recursion can be TCO'd and thus run in constant stack space

10:16 timvisher: but my usage patterns are pathological in many ways, i'm sure :P

10:16 tdammers: Schrostfutz: I have no idea why one would not use tail recursion when that is possible, other than maybe pedagogical reasons

10:16 justin_smith: Schrostfutz: the question of tail recursion or not is much less important when the recursive call generates the next item in a lazy-seq (because the continuation gets turned into a thunk and no longer claims immediate stack), but otherwise I'd think tail recursion is always better

10:17 Schrostfutz: tdammers, justin_smith: okay, thank you.

10:17 tdammers: Even if it is pedagocial I think it is bad to use examples where it is the wrong approach

10:18 justin_smith: tdammers: I don't think you can build a lazy seq via tail recursion, but you can via non-tail recursion

10:18 tdammers: Schrostfutz: I'm thinking it might help illustrate the difference

10:18 Glenjamin: justin_smith: 12factor principles says log to stdout and let the process manager handle files/rotation etc :)

10:18 tdammers: justin_smith: well, as you said, when you're building a lazy seq, you don't need to TCO

10:18 justin_smith: that's how Haskell gets away with not doing TCO at all (or always doing TCO, depending how you look at it)

10:18 justin_smith: Glenjamin: OK, but screen/tmux are not process managers :P

10:19 Glenjamin: heh, don't disagree there

10:19 Schrostfutz: tdammers: But then you should make sure that you mention tail recursion would be the better option

10:19 tdammers: Schrostfutz: agree

10:20 justin_smith: Schrostfutz: here's the thing - sometimes laziness is better, and laziness can't really be tail recursive

10:20 I don't think...

10:20 tdammers: in a way, it's not recursive at all

10:21 as in, the recursive call is deferred

10:21 transparent continuation-passing or something like that

10:21 Schrostfutz: justin_smith: yes, but we have not been introduced to anything lazy yet.

10:22 justin_smith: fair enough, sounds like bad choice of example then, unless they are leading to a brilliant gotcha

10:22 like "see how this blows the stack, now lets look at ways of preventing that"

10:22 (the whole teaching philosophy of "show why you need it, before showing the solution")

10:24 * tdammers is having a weird deja-vu

10:25 tdammers: someone at work just pasted an article about the problem/solution ordering thing

10:25 justin_smith: tdammers: that's what I was thinking of

10:25 the whole thing with video games, keys, doors

10:25 tdammers: yeah, that's the one

10:25 headaches and aspirin

10:25 monads and monad tutorials :D

10:26 justin_smith: tdammers: of course I see exceptions to this in the real world "show your child the consequences of running into traffic, then teach them to look both ways"

10:26 but in the digital world, we are lucky :)

10:26 tdammers: "have your child run into the traffic, then you won't need to bother with the teaching anymore" :x

10:26 justin_smith: lol

10:27 tdammers: also explains why security is such an orphan child in the digital world

10:27 it's impossible to create the headache in a safe way there

10:28 justin_smith: That's true - by the time it hits, you are screwed. And you are strongly disincentivised to talk about the experience (admitting you had the problem makes you look bad in the market).

10:31 adamretter: I have inherited some Java code which is using Clojure as a library. I have a com.github.krukow.clj_lang.IPersistentVector and I somehow need to sort this by a key function (in Java). Can anyone give me any pointers to how to do this?

10:32 justin_smith: adamretter: if it behaves similarly to a clojure.lang.PersistentVector you can use the methods in java.util.collections to get it into an array or ArrayList and then use it natively

10:34 adamretter: sorry, I think I was wrong about collections there - but I know there is a way to get an arbitrary clojure sequential into an array or arralist

10:35 adamretter: justin_smith: having never written a line or clojure or worked with these collections before… I might need a bit more handholding ;-)

10:36 justin_smith: adamretter: sure - check the other interfaces it implements for one (IPersistentVector is not a type, it's an interface, right?)

10:36 adamretter: experimenting in my clojure to get you something concrete right now

10:37 adamretter: if you are comfortable with a bit of clojure (into-array v) should give you a java array of Object containing the elements of the vector

10:37 ,(into-array Object [1 2 3])

10:37 clojurebot: #object["[Ljava.lang.Object;" 0x651f98f8 "[Ljava.lang.Object;@651f98f8"]

10:38 adamretter: justin_smith: yes it's an interface, but all the interfaces it implements are from Clojure, so I can't see how to tie it back to a Java array or whatever

10:38 justin_smith: erm, sorry I don't know how to write `(into-array v)` in the equivalent java

10:38 justin_smith: adamretter: you can get into-array via clojure.lang.Var, and call it with the args of Object.class and v

10:40 clojure.lang.IFn into_array = clojure.lang.RT.var("into-array"); into_array.invoke(Object.class, v);

10:40 soemthing like this

10:40 it's easier in clojure code :)

10:40 adamretter: hmm RT.var doesn't seem to be a valid method

10:41 justin_smith: adamretter: https://clojurefun.wordpress.com/2012/12/24/invoking-clojure-code-from-java/ I missed an arg

10:41 the args are "clojure.core" "into-array"

10:41 but really that article above is better than my memory right now, heh

10:43 adamretter: justin_smith: hmm but com.github.krukow.clj_lang.RT doesn't seem to have a `var` method?

10:43 justin_smith: adamretter: no! clojure.lang.RT

10:43 you use clojure.lang.RT.var to look up vars

10:43 or do they have some weird version of clojure they are using?

10:43 adamretter: justin_smith: ah so I think the issue os that the project is using this (I just googled it) https://github.com/krukow/clj-ds

10:44 justin_smith: adamretter: OK, I thought you were using clojure

10:44 adamretter: in that case, yeah I'd see what interfaces that object implements, and one of them should give you a toArray or iterator

10:44 adamretter: justin_smith: yeah so did I

10:47 justin_smith: adamretter: looks like that persistentvector has an iterator method, and it should implement count too, you could easily build up an array from its contents given those

10:47 adamretter: justin_smith: okay cool, I will try that, thanks :-)

11:06 justin_smith: TIL instead of "who am i" you can run "who killed jfk" and get the same output

11:15 TimMc: "If ARG1 ARG2 given, -m presumed: `am i' or `mom likes' are usual."

11:15 TIL

11:16 justin_smith: TimMc: sadly "who is your daddy" is rejected - too many args

11:25 adamretter: also, looking at krukow.clj_lang.RT - it has a toArray method that should work if you pass the vector in

12:51 Glenjamin: anyone know a similar shorthand to (-> (doto prn)) which works with ->> ?

12:54 muhuk: what are you doing to prn? that's cruel

12:55 Schrostfutz: Is there a way to have a helper function that's only available from within a function?

12:55 justin_smith: Schrostfutz: yes, via fn or letfn

12:55 Schrostfutz: though we don't do as much information hiding, immutability reduces its utility

12:55 Schrostfutz: justin_smith: can the function also be recursive?

12:55 justin_smith: yes

12:56 (fn foo [] (if hmm? (foo)))

12:56 or just via recur also

13:04 Schrostfutz: justin_smith: ah, thanks.

13:08 justin_smith: Am I doing something wrong or will recur not work when using the #() notation?

13:08 justin_smith: ,(#(if (< % 0) % (recur (- % 10))) 42)

13:09 clojurebot: -8

13:09 justin_smith: that would be much more readable using fn, but recur works there

13:29 {blake}: Does asyc.core use "port" and "channel" interchangeably?

13:40 amalloy: a channel probably has two ports, if i had to guess. the read and write ports

13:45 {blake}: Hmmm. We pass the channel to both puts and gets, ref'ed as "port", but for close! (and I think close! alone) it's ref'ed as "chan".

14:49 baz_: hi, have a logging related question

14:50 I'm using the tomcat-embed-jasper dependency

14:50 when I run my program (lein run)

14:50 I get jasper related logging

14:51 something like

14:51 INFO: At least one JAR was scanned for TLDs yet contained no TLDs

14:51 I would like to disable this output

14:51 currently looking at clj-logging-config

14:52 but something like (set-logger-level! "org.apache.jasper.servlet.TldScanner" :off) doesn't work

14:53 any hints on how to approach this?

15:18 justin_smith: baz_: it might be easier to make a plist file

15:24 baz_: justin_smith: not familiar with a plist file, where can I find more information?

15:25 justin_smith: baz_: http://tutorials.jenkov.com/java-logging/configuration.html

15:26 maybe that's actually a "properties" file now that I reconsider

15:32 baz_: mmm, I would prefer a programmatic way with clj-logging-config

15:47 ambrosebs: Bronsa: can you release a tools.analyzer version with this commit? https://github.com/clojure/tools.analyzer/commit/ef985c4a193470b13edb8822e9b74a1dc1368626

15:48 Schrostfutz: Can I have nested anonymous functions? If so, how do I get the arguments?

15:48 {blake}: Schrostfutz: You can't nest the #() notation but you can nest (fn[x y]...) till the cows come home.

15:49 ,((fn[a b] ((fn [x y] (+ x y)) a b)) 2 3)

15:50 clojurebot: 5

15:50 {blake}: Schrostfutz: Terrible example, but you get the idea?

15:51 Bronsa: ambrosebs: sure

15:52 ambrosebs: Bronsa: thanks, just requires a few changes and I'd rather fix them now.

15:55 {blake}: Given an vector of symbols, is there an elegant way to sort them in an arbitrary way? So, the vector might use :a :b :c :d, but I need them in :d :a :c :b?

16:00 Schrostfutz: {blake}: yes I do.

16:01 ambrosebs: Bronsa: will that commit break core.async?

16:02 Bronsa: unlikely

16:02 {blake}: ,(sort-by {:a 2 :b 4 :c 3 :d 1} [:a :b :c :d])

16:02 clojurebot: (:d :a :c :b)

16:03 {blake}: Neat.

16:05 luma: ,(defn ->order [s] (zipmap s (range)))

16:05 clojurebot: #'sandbox/->order

16:05 luma: ,(sort-by (->order [:d :b :a :c]) [:a :b :c :d])

16:05 clojurebot: (:d :b :a :c)

16:08 {blake}: luma: Nice!

16:15 Schrostfutz: What is wrong with something like this: #(func param %)? The compiler does not expect % it seems...

16:18 hiredman: the compiler actaully has nothing to do with %

16:19 by the time the reader is done with #(func param %) % is gone

16:19 ,'#(func param %)

16:19 clojurebot: (fn* [p1__25#] (func param p1__25#))

16:20 hiredman: the error is almost certainly in the surrounding context, and it is hard to say what it is because you have edditorialized it and halfway incorrectly diagnosed it

16:20 likely you are using -> or ->> without understanding that they are purely syntactic transforms

16:21 or you are trying to nest #() forms, which isn't allowed, or func just doesn't take the arguments you thing it does

16:21 to narrow that down you need to paste bin the actual error you get

17:52 gfredericks: does cljs have a mechanism for programmatically generating docstrings, via alter-meta! or equivalent?

18:05 neoncontrails: Has anyone worked through the canonical Functional Data Structures textbook?

18:06 Sorry... *Purely* Functional Data Structures (Okasaki)

18:06 amalloy: ~anyone

18:06 clojurebot: Just a heads up, you're more likely to get some help if you ask the question you really want the answer to, instead of "does anyone ..."

18:06 neoncontrails: Heh. Touche, clojurebot

18:07 dnolen: gfredericks: at runtime? no since docstrings aren't a thing at runtime

18:07 clojurebot: Excuse me?

18:07 neoncontrails: I'm wondering the applicability of Okasaki to Clojure specifically, as all the textbook exercises are ML with a dash of Haskell

18:07 gfredericks: dnolen: the use case is reducing duplication in docstrings; I'm guessing I'll just have to put up with it?

18:08 amalloy: clojure still has functions. you can do the exercises in clojure, and mostly just skip the types. you do have to at least recognize ML type signatures to know what you're supposed to implement

18:13 neoncontrails: amalloy: would the data structures translate well into a React environment.? I'd like to have a better understanding how to exploit the monolithic "app-state" paradigm

18:15 amalloy: beats me. i'd guess not, but i'm no expert

18:25 didibus: I've been wondering inside a let expression, it seems I cannot do _ (println "hey") more then once. Anyway around it?

18:27 Hum, nevermind, it seems it works

18:27 I must have something else that's the issue

18:29 TEttinger: ,(let [_ (print "hey, ") _ (print "party ") _ (print "people!") _ 5] _)

18:29 clojurebot: hey, party people!5

18:32 didibus: I just found my problem, I was trying to bind a name that I have a function defined for, so it ws complaining about how it can't cast the bind into an IFn

18:32 McDougal: Hi, is anyone here using luminus?

18:32 didibus: And that was causing the let to fail past that point

19:19 Do (deftest) run in the order they are declared? And do they run one after the other or in parralel?

19:21 vilmibm: didibus, run in the order you declared, sequentially

19:21 didibus: ok, thanks

19:40 dnolen: gfredericks: need some more context on what you are trying to do?

19:41 you want to automatically generate docstrings for some fns w/o having to write a macro or something?

19:46 gfredericks: dnolen: I don't care what I have to write, I just have 5 functions whose docstrings are 95% identical

19:46 I'll show you how I'm doing it in clj-jvm

19:47 dnolen: gfredericks: you can this with a macro then

19:47 gfredericks: https://github.com/clojure/test.check/blob/6a2f74d4088c11bb16b26899c63fe6887ac17c25/src/main/clojure/clojure/test/check/generators.clj#L598

19:47 dnolen: just add :doc meta

19:47 gfredericks: oh right

19:47 dnolen: s/can/can do

19:47 gfredericks: I'm so used to punching vars that I don't think of macros for that :)

19:47 cool, thanks

19:48 amalloy: gfredericks is just embarrassed to admit he doesn't know how to use macros

19:48 gfredericks: it's a bit less composable, but it works in this case

19:49 numberten: is there a core function for this functionality: (fn [pred f x] (if (pred x) (f x) x))

19:49 it seems like that would be common, but I can't think of anything off the top of my head

19:50 dnolen: gfredericks: yeah alter-meta! unfortunately in ClojureScript works on runtime ref types

19:51 so that excludes using it for banging on compiler information like var metadata

19:51 gfredericks: right

19:52 amalloy: well alter-meta! does the same thing in clj-jvm, right? it's just that vars are also runtime ref types

19:53 gfredericks: yeah

20:09 oh actually

20:09 in clojure you can also use expressions for the docstring

20:09 in either metadata position

20:09 I wonder if that works in cljs too

20:11 celwell: Hello, I recently added some java code to my lein project (using :java-source-paths in project.clj). It works well when I 'lein ring server', but when I deploy to my AWS instance I'm getting: java.lang.UnsupportedClassVersionError: ...... : Unsupported major.minor version 52.0

20:12 hiredman: because the java on your aws instance is older than the java on you local machine where you are compiling your java class files

20:13 amalloy: you can fix it by adding a thing in your project.clj saying what version of java to target when compiling

20:13 celwell: How can I target lower version? I tried :javac-options ["-target" "1.6"] but it didn't help.

20:13 maybe I need to try some even older version

20:14 hiredman: if I recall it is actually kind of a pain to do that, have you considered upgrading your aws instance to a newer version of java?

20:14 celwell: I will look into that, I'm actually on AWS Elastic Beanstalk, using Tomcat 7 server, I'm not sure how easy it is to choose java version.

20:15 hiredman: 52.0 is java 8 (jdk 1.8), and I think java 7 is already EOL

20:15 gfredericks: nope :(

20:16 amalloy: that -target stuff works fine

20:18 hiredman: apparently you can run in to issues if you don't also set the bootclasspath to point to the rt.jar for the correct java version, but I don't think I have every run in to that

20:19 https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javac.html#BHCIJIEG

20:22 amalloy: yeah, in theory that is a problem but in practice it has never mattered to me either

20:50 dnolen: people should try ClojureScript master if they can - we're going to ship a new release on Friday - many fixes

20:54 gfredericks: is there a portable way for checking if a transient set contains an element?

20:55 dnolen: @gfredericks hrm don't think so

20:55 gfredericks: welp that's what cljc is for I guess :)

20:55 dnolen: https://github.com/clojure/clojurescript/releases/tag/r1.7.166

20:56 actually just try the prelease should hit Maven shortly

20:57 McDougal: How is the web story for clojure nowadays ref basic stuff like emailing html templates, image resize, etc? And how does performance compare with a Go web app?

21:10 owlbird: what's the best way to do if-return earlier in clojure?

21:13 McDougal: Is there an elseif in Clojure?

21:13 justin_smith: McDougal: cond

21:14 McDougal: justin_smith: Aha, gotcha. Thanks. Btw, would you use jetty or immutant or http-kit for a persistence heavy CRUD app?

21:14 gfredericks: I'm finally adding generators to test.check for collections of distinct elements (of particular sizes, optionall)

21:14 it's harder than it sounds

21:15 justin_smith: McDougal: I'd use ring, use the jetty adaptor during dev because that's just easy, and then leave the production decisions based on how you want to deploy

21:16 McDougal: justin_smith: Thanks. Being new to lisp, how long do you think it may take for the simplicity of lisp to kick in. I can get an app working, but at the mo, it sure does feel v diff. As its so new, more thinking everything through vs simplicity. I'm hoping to have that aha moment ref lisp vs reg OO

21:18 justin_smith: McDougal: well, of course complexity is different from unfamiliarity. There are a lot of little revelations to find. One of them is realizing that you rarely need to hunt through code for a needle in a haystack to see why somthing ended up the state it is in - immutable values mean you just look at the immediate context and call stack

21:20 McDougal: justin-smith: I'm about a week in and stuff gets hard wired quicker on a real project. So I'll just keep at it till its fluent

21:22 Is clojure-toolbox the best place to look for libs?

21:24 owlbird: It's fantastic to write web app by using clojure (compojure) :-)

21:26 sotojuan: :-)

21:26 justin_smith: McDougal: I start with google to find leads, then crossclj.info to see who uses the lib and how, then github to do a sanity check on the repo / code / developer activity

21:27 McDougal: also, sometimes the best option is to just use interop with a java lib - it's not hard, and there's java libs out there for pretty much everything it would be reasonable to do with clojure

21:28 McDougal: I know that as a newcomer the exciting part is fp, but clojure makes a good lightweight glue for using a few java libs too

21:29 (lightweight in developer time / energy, not lightweight in machine resources)

21:30 McDougal: justin_smith: Thank you, am checking crossclj.info. When you say who the lib is used by, you mean companies or inidividual devs. I agree, it would be good to get a handle on java interop for max flexibility.

21:30 justin_smith: McDougal: I mean look at how widely used it is, as well as what code that uses that lib looks like

21:32 McDougal: justin_smith: Thanks, that's a more holistic approach to gauge lib quality. What have you settled on for rendering views? I'm looking at Hiccup and Selmer.

21:33 justin_smith: McDougal: I'm a contributer to the caribou project (not super active right now, we used to have a company funding us but no longer...) - we have our own markup lib called antlers that I use, but it's similar to selmber. I like hiccup for ad-hoc stuff, especially making templates out of existing html and then doing data transformations. Also I use reagent, which uses hiccup syntax. So yeah, hiccup is great too.

21:34 but for something a designer or frontend-only dev might touch? antlers or selmer is better for that

21:35 McDougal: justin_smith: I looked at caribou about a year ago, it has a v nice admin and looked really slick for doing crud type apps. So clojure community still not leaning towards frameworks for productivity?

21:36 justin_smith: no, for the most part not. Though liberator is a great "framework" for doing REST right.

21:38 McDougal: Prob because its so easy to stitch things together with just the needed libs. Thank you for the tips, I'm having a lot of fun with clojure, its stretching my mind in a v diff way

21:39 justin_smith: McDougal: for some things though, like security, a framework would be so much better

21:39 because security is a weakest link kind of thing, and that's where loose ad-hoc collections tend to fail

21:40 McDougal: justin_smith: I saw the talk on that. Have you found a good approach, mix of libs to plug that hole?

21:41 justin_smith: kind of - I mean, bcrypt, make sure you have nginx with ssl as a reverse proxy (because jvm ssl is a pain in the ass, not worth it)

21:42 the ring middlewares for importing params, clojure.java.jdbc for prepared statements instead of string concatenation for sql

21:42 McDougal: Yeah I always use that, got into bcrypt habit from rails exp. Haven't done the ssl on nginx as reverse proxy tho.

21:43 So with string concatenation sql injection is still wide open?

21:43 justin_smith: McDougal: I mean, if you string concatenate and get stuff from a user, how can any environment prevent vulns there?

21:44 McDougal: Gotcha, that makes sense. Ref ssl reverse proxy, does that mean running the entire app in ssl or just persistence?

21:45 justin_smith: it means all access through ssl via the reverse proxy, yeah

21:45 and letting nginx do all the work

21:46 McDougal: That's a good default. What are you using for persistence, java.jdbc or some other lib?

21:48 Am leaning towards yesql

21:49 sobel: i just write functions that isolate the queries/jdbc access

21:50 justin_smith: right now? a mixture of caribou's persistence layer (a map oriented thing built on top of jdbc) for the data that really matters and monger (mongodb) for stuff that needs to be fast cheap and easy and we could totally live if it all crashed and burned and we had to recreate the dataset

21:52 owlbird: I've tried compojure/jdbc a few days, and figure out that the best structure of a web app only has 3 files, project.clj, db.clj, handler.clj, and write all business logic and jdbc/query in the handler.clj.....

21:53 justin_smith: owlbird: that works until you have thousands of lines of handler, heh

21:53 McDougal: Gotcha. I'll have to try monger, first foray into nosql. Mostly postgres so far. I'll check into java interop in clojure for the brave, he does pretty good coverage on it

21:53 justin_smith: mongo has some bit gotchas so far in my experience - unless we just use it all wrong :P

21:54 eg. updates leaving a thread open trying to read a socket, and the thread and socket never being released until the app crashes because it runs out of one or the other...

21:54 McDougal: justin_smith: Have you seen Rethinkdb, its an interesting nosql project

21:54 justin_smith: yeah, I've seen it

21:54 almost tried it once

21:54 McDougal: How about Cassandra or any graph dbs?

21:54 justin_smith: McDougal: from a clojure point of view. datomic is pretty interesting

21:55 McDougal: justin_smith: What's the pricing model on Datomic?

21:55 justin_smith: McDougal: we are doing a lot of heavy duty graph stuff, but found that our graphs were too dense for the graph dbs to really pay off -- once a graph is dense enough regular tables make sense again

21:55 McDougal: Datomic is immutable db right?

21:56 Which graph dbs did you try out?

21:56 justin_smith: I think that's a good way to put it - yeah - of course you can do inserts / drops / updates, but it's all done with snapshots of time

21:56 McDougal: Is the benefit in Datomic performance or an audit trail?

21:57 justin_smith: McDougal: the stuff about graph dbs is second hand actually, my team / tech lead tried them before I got hired, and I don't remember all the names, but I know they tried a few

21:57 McDougal: correctness

21:57 and avoidance of some common concurrency related mistakes that happen even with a proper transactional db

21:58 McDougal: I'll check it out, at v least as its Rich Hickey. The graphdb I was checking out is orientdb for a recommendation engine

22:00 mysamdog: Hey, does anyone here use dommy?

22:00 I can't seem to get scroll events to work, but click events work just fine

22:01 McDougal: V interesting, a free tier on Datomic, I'm def going to try that, would be a good learning experience

22:03 mysamdog: (dommy/listen! (dommy/sel1 :body) :click check-scroll) works, but (dommy/listen! (dommy/sel1 :body) :scroll check-scroll) doesn't

22:03 McDougal: justin_smith: Is Datomic considered a relational or nosql db?

22:09 mysamdog: Nvm, I figured it out

22:09 I replaced (dommy/sel1 :body) with js/window

22:12 McDougal: justin_smith: Thanks for all your tips, much appreciated. Going through the Datomic docs.

22:59 matthavener: #

22:59 whoops

23:23 wegry: Hey all, I'm wondering if anyone has used cljs-ajax here?

Logging service provided by n01se.net