#clojure log - Apr 20 2014

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

0:51 kenrestivo: does this already exist in something else, some other library? https://www.refheap.com/77773

1:13 oinksoft: In C i might have enum LogLevel { DEBUG, INFO, WARNING, ... } and then i can do DEBUG + 1 to get INFO, etc. How would you do this in Clojure?

1:13 where you have some constant values that can refer to each other

1:16 beamso: why wouldn't you just use INFO instead of DEBUG + 1?

1:16 kenrestivo: oinksoft: pretty sure there are c-like enums in java. you could always do a java class if you want that behavior, and access it from clojure

1:17 beamso: i haven't seen anyone do that sort of enum math in java

1:18 kenrestivo: otherwise you could hack something like (def loglevels {:debug 1, :info 2, :warning 3}), and (set-loglevel (inc (:debug loglevels))

1:22 i've done it in java before as public enum SomeEnum {FOO, BAR, BAZ}; and then i guess you could do SomeEnum.FOO + 1, but not sure the use case

1:31 hiredman: in clojure enum type things are typically not numbers, but keywords, so no math

2:07 oinksoft: hiredman: hm ok

2:07 hiredman: well the math part (comparison) can be useful: http://www.bpaste.net/show/Jh105vI7FoTM77sl5iAN/

2:07 hiredman: pardon the poorly written macro? this is my first one so i don't know the idioms 100%

2:07 kenrestivo: hm ok, this is the sort of use case i was thinking of (that paste)

2:08 TEttinger: oinksoft: ##(let [log-level [:debug :info :warning] inverse-log-level (apply hash-map (interleave log-level (range))) access-log (fn ([log-key] (get inverse-log-level log-key :not-found)) ([log-key modifier] (get log-level (+ (inverse-log-level log-key) modifier) :not-found)))] (access-log :debug 1))

2:08 lazybot: ⇒ :info

2:08 TEttinger: oinksoft: ##(let [log-level [:debug :info :warning] inverse-log-level (apply hash-map (interleave log-level (range))) access-log (fn ([log-key] (get inverse-log-level log-key :not-found)) ([log-key modifier] (get log-level (+ (inverse-log-level log-key) modifier) :not-found)))] (access-log :debug 99))

2:08 lazybot: ⇒ :not-found

2:09 TEttinger: some fun tricks there, interleave is a useful function for generating hashmaps

2:09 oinksoft: TEttinger: i see that there are many fun tricks in there...

2:10 TEttinger: heh, it would be clearer split up

2:10 oinksoft: ;)

2:10 TEttinger: but it fits in one IRC message so there

2:10 oinksoft: but you can compare levels w/ that?

2:10 TEttinger: yes

2:11 oinksoft: what does that look like?

2:11 TEttinger: access-log with one arg, like :debug , produces an int or :not-found

2:11 starting at 0, going to the max index in the vector log-level

2:11 I am absolutely certain this can be done better by a more experienced clojurer

2:12 in particular I bet macros could help, but I haven't touched them

2:12 (there's probably some way I'm not seeing yet)

2:13 oinksoft: i see, you have just constructed a reverse lookup

2:14 thanks TEttinger, that's nice and simple

2:14 although i do like my enum macro ;)

2:17 guns: FTR, it's nice to have things like (def FATAL 0) as actual source code

2:18 oinksoft: you speak for the record?

2:19 guns: this chat room is logged, so yes :)

2:19 oinksoft: :)

2:19 i guess the nice thing in C is you get the type too

2:19 when you use an enum

2:20 guns: well, you can ^:const simple Clojure values

2:20 and you can use core.typed or schema for the typing

2:20 oinksoft: and you could wrap thatall up in an enum macro ;)

2:20 guns: (or a simple ^long I suppose)

2:20 oinksoft: i'll look at core.typed and schema

2:20 guns: haha yes. Although I had my fill of that kind of thing in ruby

2:21 cancer of the semicolon, as they say

2:21 oinksoft: hehe

2:22 well i am on that side of things but now i am working a job in clojure and i see that the clojure community often seems to favor extremely high level abstraction

2:22 working in ruby for years i had the same conclusion as you

2:23 but i feel some pressure to add lots of syntax to clojure programs? do you notice this guns ?

2:23 *syntactical sugar

2:23 guns: I think the idea behind the community's love for abstraction is building things around protocols, etc

2:23 so, no

2:23 I think it's actually the opposite!

2:23 oinksoft: maybe this is just the tone of instructional books

2:23 i am reading two from manning press

2:23 it reminded me of the ruby community, was turning me off tbh

2:24 guns: There are differing opinions, but those of us who suffered through Rails projects favor being explicit

2:25 I don't really see projects deffing a set of vars in this fashion for instance; it's fine for source code to be tabular

2:25 Platz: I thought the protocol stuff was for perf gains in the jvm toon

2:25 oinksoft: for me it is not an implicit/explicit thing ... it is reading rails code and one big method has been split into 80 tiny ones that only are there for that one thing in the first place. too much indirection?

2:25 guns: Platz: that too; but it gives you 80% of what you want from polymorphic code

2:25 oinksoft: but yes, indirection = soul of computer science or something

2:26 guns: oinksoft: lol; I stepped through a rails app once and found myself ~16 super calls deep

2:26 maybe it was worse

2:26 oinksoft: better to forget :)

2:27 guns: I'd say the Clojure catchphrase is "it's all data"

2:27 Platz: dare i say tiny polymorphic assemblages lead to category theory

2:28 guns: how is that? Clojure's protocols don't feel like a "kind-of" relationship

2:29 not allowing inheritance helps alot

2:30 arrdem: guns: just because it's not supported doesn't mean people don't use it..

2:30 guns: and we do have hierarchies which are entirely inheritance based..

2:31 guns: arrdem: that's true; I'm just saying extending protocols isn't a feature

2:31 using the existing Java class hierarchy is quite nice because it's nicely designed

2:33 arrdem: eh... it depends. I guess I agree in spirit that protocols aren't an inheritance based extension mechanism but I'd also argue that I've personally gotten a good bit of millage out of my own additional implementations of my own and others protocols.

2:33 so they're still very much a client driven extension mechanism

2:33 abet in a much more static manner than say multimethods

2:35 guns: I'm open minded. It's just nice that writing Clojure code isn't usually a practice of "extend these magic base classes and mixin this magic module"

2:36 arrdem: oh totally

2:37 it's much more a "oh here's this map datastructure, do what you will with it and here's how to get/make more"

2:37 oinksoft: would it be weird to do (def some-fn (let [stuff (atom {})] (fn ...))) ? or is this common?

2:37 arrdem: and I think that the focus on the data rather than the structure of the manipulating fns makes it much more flexible and powerfull.

2:37 oinksoft: for enclosing somethig in that function

2:38 i usually see `stuff' defined at the same level as `some-fn', not local to `some-fn'

2:38 arrdem: oinksoft: so I'm not sure you can do exactly that..

2:38 guns: oinksoft: mutable global state. have fun!

2:38 arrdem: oinksoft: but yes you can have lets enclosing defs

2:38 guns: there are legitimate uses for that... memoization caches for instance

2:38 oinksoft: guns: sorry, stupi dexample w/ the atom

2:38 guns: i mean more like constants onl important for that function

2:39 arrdem: oinksoft: it'd be very strange to encapsulate them like that

2:39 oinksoft: if you have some mutable state like an atom... that's almost. almost. ok.

2:39 oinksoft: anything else that's constant and that you may ever want to see somewhere else..

2:39 oinksoft: not kewl brah

2:40 oinksoft: hm ok, i felt like maybe this would make for more concise definitions, shorter constant names

2:40 if it is not idiomatic then ok!

2:41 guns: global state isn't necessarily evil; it's just that Clojure programmers often fall back to it because there is no instantiable class like thing OOTB

2:41 oinksoft: hm i am very uncomfortable w/ using global state

2:42 erlang makes it much harder to use global state

2:42 guns: global constant data is great; my knee jerked because you were using an atom

2:42 oinksoft: *mutable state

2:42 arrdem: guns: the real insight of Clojure, and kinda the falilure of OOP imo is that you don't usually need global mutable state at all

2:42 guns: some times you do need mutable state

2:43 and that's fine, but usually you can get away with parameterizing everything on a single mutable parameter

2:43 which escapes this "big mutable global singleton" antipattern

2:43 and handles much more nicely in a threaded environment :D

2:43 guns: arrdem: I have no quarrel with mutable state; there's no getting around it for high performance work for instance

2:43 * arrdem digs for the last lib he pr'd

2:44 arrdem: guns: and nether do I. I just contend strongly that I've only rarely seen instances where the mutable state had to be truly global scope and couldn't be managed nicer parametrically.

2:44 oinksoft: how do you like to structure your param lists? i do (action/description-args..., subjects)

2:44 but some people like to put the subjects first

2:45 arrdem: oinksoft: typically you'll put the highest variance argument first.

2:45 oinksoft: ah that explains why this works

2:45 arrdem: oinksoft: so if you have some map you're manipulating and a bunch of arguments that describe the manipulation you can use the -> macro nicely

2:46 oinksoft: as-> exists because that isn't always possible... same with ->>

2:46 oinksoft: hehe sometimes i htink i am overusing -> :)

2:46 arrdem: no such thing :D

2:47 guns: There's also the convention of seqable things at the end: (->> [] (map pred …) (remove pred …) …)

2:48 *sequential things

2:48 arrdem: guns: this is a good case in point...

2:48 guns: https://github.com/markmandel/brute/blob/master/src/brute/entity.clj#L5

2:49 guns: having a global mutable def is flat out wrong.

2:49 guns: see the thread... https://github.com/markmandel/brute/issues/1#issuecomment-40435084

2:50 guns: yes, totally agree. I've been using stuart sierra's component library with great success

2:50 arrdem: heh yeah Stuart's reloaded model takes this to the extreme :P

2:51 guns: arranging components together with async channels is making typical software construction really obvious

2:52 then prismatic came around and delivered 70% of what I want from a type system

2:52 arrdem: guns: which lib.. schema?

2:52 guns: it's been hard to drift away from Clojure with all this great stuff

2:52 arrdem: yes

2:53 oinksoft: clojure reminds me of perl in many ways

2:53 guns: I can see that … at a meta level

2:54 oinksoft: there is a strong emphasis on practicality over simplicity

2:54 guns: hmm?

2:54 those are synonyms

2:57 oinksoft: guns: ##(count (ns-publics 'clojure.core))

2:57 lazybot: java.lang.SecurityException: You tripped the alarm! ns-publics is bad!

2:57 oinksoft: ah what do i know, but it's 591 here

2:58 guns: that's the whole "100s of functions on a single data structure|abstraction" perlis quote

2:58 oinksoft: and lots of convenient syntax over simple syntax

2:59 guns: oinksoft: I'm not sure I follow that; the syntax is quite convenient, but it's also simple

2:59 Platz: elepnant in the room is macros

3:00 guns: clojure.core stays pretty tasteful IMO

3:00 AmandaC: Platz: no, it’s an elephant. Stop calling it something else, you’re hurting it’s feelings.

3:01 Platz: what happens when trying new keyboards

3:02 oinksoft: Platz: yes, tha'ts another thing in clojure that reminds me of perl

3:02 Platz: perl is a very strong language for writing DSLs

3:03 * AmandaC doesn’t approve of this definition of “DSL"

3:03 AmandaC: Amanda angry! Amanda… too tired to smash, maybe take a nap instead

3:04 Sorry, I’m a bit loopy on sleep deprevation

3:06 guns: Perl hackers have stronger stomachs than Clojurists though

3:06 magic thlobals for instance

3:08 Platz: perl makes me think of 2600 and phrack

5:54 ptcek: very noob question.. I have a string and have to pass it as Reader or InputStream instance to some java constructor... how can I do it?

6:00 katratxo: ptcek: try http://clojure.github.io/clojure/clojure.java.io-api.html#clojure.java.io/reader

7:40 luxbock: hello, has anyone here got experience with using C++ in combination with Clojure? I have an application where I'd like to formulate/manipulate the inputs of a C++ program (which doesn't exist yet) from Clojure, then have the C++ program perform some heavy computing on inputs and then have the C++ output data that I'd then like to further use from Clojure

7:40 I myself have no experience with C++

7:40 I'm aware of https://github.com/ztellman/gloss and https://github.com/ztellman/vertigo

7:41 they talk about doing interop with C structs/libraries

7:41 would these work just as well for C++, or are there some gotchas I should be aware of?

7:50 someone telling me that doing this is not a good idea would be good advice as well :)

9:10 gfredericks: technomancy: AND ALSO

9:10 * gfredericks continues a conversation from two weeks ago

9:11 gfredericks: technomancy: the postgres jdbc driver, when using the postgres uuid column type, returns java.util.UUID objects; so under the Technomancy Plan these objects would have to be converted to strings on every read just to maintain consistency

10:06 owl-v-: mm~ another day of clojure :-)

10:11 rrfrfgrfggefddfwsssssqsaqswqqwwwww2qq````````````11````111

10:11 ops

13:15 kras: Hi folks! Is there an equivalent of consp in clojure?

13:15 Like say cons?

13:16 I am trying to test if something is a seq? or vector?

13:16 I can always use an or here

13:16 just wondering is there is something else

13:16 bbloom: ~colls

13:16 clojurebot: colls is seqs and colls

13:16 bbloom: ~seqs

13:16 clojurebot: seqs is http://www.brainonfire.net/files/seqs-and-colls/main.html

13:17 bbloom: kras: that page should reveal all

13:17 nDuff: kras, do you just want to know if it's seqable? The gotcha there is that several other things, such as strings, can also be treated as seqs.

13:18 kras: just want to know if it is seq? or vector?

13:18 * llasram is skeptical

13:19 llasram: What are you actually trying to do with that information?

13:19 * bbloom is similarly dubious

13:20 kras: sequential? seems to be serving my purpose

13:20 thanks for the link bbloom

13:21 i am trying to flatten a given sequential just as an exercise

13:21 so had to first check for this

13:22 bbloom: kras: as an exercise, sequential? is exactly what you want, but in practice i've found that it's almost always better to either A) treat seqs and vectors separately or B) coerce w/ seq

13:23 kras: bbloom: thanks I will keep that in mind

13:24 I have come up with my own version of flatten wihtout recur ofcourse

13:24 please comment, appreciate your inputs

13:25 https://www.refheap.com/77988

13:26 this is the first version

13:26 is it possible to use recur at all for flatten?

13:27 bbloom: kras: recur requires tail recursion and is eager. flattening is not strictly tail recursive b/c you can flatten in more than one position per call

13:28 kras: your implementation is eager as well. you should try an eager version that does not use reverse (hint: vector + conj)

13:28 kras: after that, try a lazy version using lazy-seq

13:29 kras: bbloom: when you say eager does that mean fully realizing a seq?

13:30 bbloom: ,(take 5 (flatten (range)))

13:30 clojurebot: (0 1 2 3 4)

13:30 bbloom: kras: that takes 5 items from the result of flattening an infinite sequence

13:30 kras: your code can't do that b/c it tries to walk the entire seq

13:31 kras: bbloom: oh ok, got it.

13:31 I will give it a shot

13:31 bbloom: there are reasons you may want an eager flatten, but generally clojure code prefers to keep seqs lazy until the end:

13:31 ,(into [] (take 5 (flatten (range))))

13:31 clojurebot: [0 1 2 3 4]

13:31 bbloom: the into [] makes it eager

13:31 but the internal laziness of the function pipeline is maintained

13:31 kras: eager eval should be defintely faster if I am correct?

13:32 bbloom: kras: it can be, but clojure implements some lazy optimizations such as chunking, etc

13:32 mpenet: luxbock: kind of, via a dll (on windows *sigh*) + a super thin jni wrapper in java, then it's just normal java interop calls from there

13:32 luxbock: it is gross, but it is fast

13:35 I had no acces of the c++ sources and it is crazy complex stuff (klystron simulation code) otherwise I would probably have taken another route.

13:39 Jaood: bbloom: do you still love rails? ;)

13:39 bbloom: Jaood: for what it's good at: absolutely

13:39 Jaood: came across this: http://www.brandonbloom.name/blog/2011/09/24/one-year-after-accidentally-falling-in-love-with-rails/

13:39 bbloom: Jaood: if you've got to make a crud app in a hurry, there is no substitute

13:40 Jaood: bbloom: but you don't miss ruby right? :)

13:41 bbloom: Jaood: i much prefer clojure, if that's what you're asking :-P

13:43 Jaood: bbloom: looks like rails is highly praised for that, gettting crud done quick and safe

13:46 kras: bbloom: a slightly improved version eliminating reverse

13:46 will thing about lazy seq

13:47 think*

13:47 https://www.refheap.com/77991

13:49 bbloom: (doc empty?) ; kras: note the seq idiom

13:49 clojurebot: "([coll]); Returns true if coll has no items - same as (not (seq coll)). Please use the idiom (seq x) rather than (not (empty? x))"

13:50 bbloom: kras: comparing against () isn't a great idea b/c nil is also an empty seq. also, generally, we prefer next over rest b/c it coerces () to nil, which tests as logical false

13:50 kras: ,(= () nil)

13:50 clojurebot: false

13:51 bbloom: ,(boolean nil)

13:51 clojurebot: false

13:51 bbloom: ,(boolean ())

13:51 clojurebot: true

13:51 bbloom: ,(seq [])

13:51 clojurebot: nil

13:51 bbloom: ,(rest [1])

13:51 clojurebot: ()

13:51 bbloom: ,(next [1])

13:51 clojurebot: nil

13:53 kras: bbloom: I realize that empty () or [] is not false like in other languages

13:53 but what is the problem with (= () lis)

13:54 sorry confused a litle bit

13:54 llasram: ,(= '() (range))

13:54 clojurebot: false

13:56 bbloom: kras: try (flt nil [])

13:56 amalloy: kras: writing flatten with an accumulator seems weird to me. it can't be tail recursive anyway, so why not just cons onto the result of recursion?

13:56 llasram: kras: I think it's two things: (a) checking exactly the property you care about, and (b) following the common language idioms to improve code readability

13:57 bbloom: kras: instead of (= () lst), try (nil? (seq lis))

13:58 kras: which is the same as (not (seq lis)) which is empty?

13:58 amalloy: bbloom: i assume there's some contextual reason i'm missing why (nil? (seq xs)) makes sense over (empty? xs) here?

13:58 bbloom: amalloy: just for illustrative purposes

14:00 kras: bbloom: got your point (flt nil []) gives the correct result now

14:00 will probably take some time to digest this info

14:02 amalloy: could you please elaborate on what you mean by consing over the result of recursion

14:02 sorry noob here

14:02 amalloy: kras: like (cons x (flt ...))

14:02 rather than (flt ... (conj acc x))

14:02 kras: amalloy: oh ok, I agree,

14:03 I started out trying tail recusion first

14:03 then realizes this is not possible

14:03 amalloy: sensible

14:03 kras: but that acc remianed there

14:04 thanks a lot guys, that was really insightful discussion

14:04 will ponder over this for the day

14:05 time to go bed, have a nice day

14:06 bbloom: that's not a long day of pondering :-P

14:06 kras: :-) or should I say for the next day

14:07 this 4clojure is very addictive i say

14:07 did not realize it was so late

14:12 boyscared: might as well just keep going

14:27 akazlou: hi, guys, I see an "idiom" of recur-ing into the loop on the seq checking (if (next <some seq>)) which returns nil, if it is the last element in the seq, and then (next <some seq> is called for recur, of course. Is it not too expensive to do this call, and doing them 2 times? Is it better to use (not= (count <some seq>) 1) as a guard for recur instead?

14:30 `szx: isn't count O(n)?

14:30 ,(doc count)

14:30 clojurebot: "([coll]); Returns the number of items in the collection. (count nil) returns 0. Also works on strings, arrays, and Java Collections and Maps"

14:31 `szx: thought i read that somewhere

14:32 akazlou: 'szx you might right, actually maybe (next seq) is cheaper than count

14:32 might be

14:32 then it would make sense to do

14:32 `szx: http://stackoverflow.com/a/1273848/318603

14:34 akazlou: yeah, i'm sure there's a good reason though i can't say for sure i know what it is

14:36 akazlou: ,(map #(instance? clojure.lang.Counted %1) [[] '() {} (seq [])]

14:36 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

14:36 akazlou: ,(map #(instance? clojure.lang.Counted %1) [[] '() {} (seq [])])

14:36 clojurebot: (true true true false)

14:37 akazlou: so map, vector and list implements Counted, but seq not

14:38 my bad

14:38 (map #(instance? clojure.lang.Counted %1) [[] '() {} (seq [])]

14:38 ,(map #(instance? clojure.lang.Counted %1) [[] '() {} (seq [1])]

14:38 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

14:38 akazlou: ,(map #(instance? clojure.lang.Counted %1) [[] '() {} (seq [1])])

14:38 clojurebot: (true true true true)

14:39 akazlou: all of them true, just seq on empty list is nil

14:39 `szx: interesting

14:39 akazlou: so, count is O(1) for all of them in that case?

14:39 llasram: akazlou: NB that `seq` on a vector is a special case

14:39 ,(type (seq [1]))

14:39 clojurebot: clojure.lang.PersistentVector$ChunkedSeq

14:40 llasram: ,(.count (seq [1]))

14:40 clojurebot: 1

14:42 dbasch: I just wrote a few Bitcoin base58 encoding/decoding functions, maybe I should put them on github. Anyone care to review them?

14:42 https://www.refheap.com/77995

14:43 akazlou: @llasram, thank you for mentioning this

14:55 amalloy: llasram: in what way is seq'ing a vector a special case?

14:58 llasram: amalloy: The `seq` of a vector is `counted?`, but seqs in general are not necessarily

15:01 amalloy: mmmm. i don't know that i'd call that a special case - it implies to me that there's something inside of count/Counted that treats vector-seqs specially somehow. but vector's seq is just one of N sequences that does implement Counted

15:03 seq on a map is counted too, and same for a list (ha ha). and you can make arbitrary instances of Counted yourself

15:03 llasram: That's fair. I just noticed a risk of someone inferring all seqs to be Counted. I trying to just clarify that the Vector-specific seq implementation specifically implements Counted

15:04 But that isn't a guaranteed property of seqs

15:18 gfredericks: okay so I think I'm going to try to write a multiplexing nrepl middleware

15:19 Q: should I call it muxrepl or mrepl or something else?

15:20 whilo: i have some exceptions in my test-output as well as sometimes on runtime (nrepl-server output in emacs), how do i turn on stacktraces? i tried to put the code in a try-catch block, but this hasn't worked so far. it is run in core.asyncs threadpool in these cases

15:20 llasram: gfredericks: What's it going to multiplex?

15:21 hiredman: gfredericks: manifold

15:21 llasram: whilo: Are you not getting the full traces in your *nrepl-server* buffer?

15:21 whilo: nope

15:21 llasram: Hmm. Odd

15:21 whilo: just the error message

15:22 like: #<NullPointerException java.lang.NullPointerException>

15:22 llasram: Weird. That looks like something is just `pr`ing the exception object

15:22 gfredericks: llasram: sessions

15:23 llasram: biggest immediate win: backgrounding a long-running expression while it's running

15:23 whilo: llasram: yes

15:23 gfredericks: llasram: but I also want to use it for implementing a debug-repl

15:24 akazlou: there is (counted?) in clojure

15:24 ,(doc counted?)

15:24 clojurebot: "([coll]); Returns true if coll implements count in constant time"

15:24 llasram: whilo: Wheeeelp. That's not normal. Hmm. This is tricky :-)

15:24 gfredericks: I've already got a solution for that -- (def *result (future ...)) ;-)

15:25 gfredericks: Oh, so when the debugger gets invoked, it starts another session...?

15:25 gfredericks: hiredman: is that a ztellman joke?

15:26 hiredman: gfredericks: no, does he already have a library called manifold?

15:26 gfredericks: llasram: A) this is for _after_ the fact

15:26 whilo: some exceptions get thrown properly with stacktraces, so i assume it is core.async specific. not sure though

15:26 gfredericks: hiredman: yeah

15:26 hiredman: oh, well, not that then

15:26 gfredericks: llasram: and yeah, the debug-repl starts another session which you can switch back and forth from

15:26 hiredman: I didn't know that though, and liked the idea

15:26 llasram: gfredericks: Neat

15:26 dbasch: whilo:it’s probably this: https://github.com/clojure/core.async/blob/76b25bf91c670b0c3542ed9cb687ff29fb2183a7/src/main/clojure/clojure/core/async/impl/exec/threadpool.clj#L33

15:26 gfredericks: llasram: I already have something better than futures actually, but it still requires forethought

15:27 whilo: dbasch: very well, thx

15:27 why is it println'ed? is there a idiomatic way to tune that?

15:28 llasram: whilo, dbasch: Ouch. That's not very friendly

15:29 whilo: i think it should default to the stacktrace, but that still doesn't make it tunable (don't know enough about logging yet, to say what was appropriate)

15:29 hiredman: gfredericks: how about manigfeald, which is, according to google, the old english word manifold comes from

15:29 lots of google juice, no idea how to pronounce it

15:29 gfredericks: hiredman: ha

15:29 dbasch: whilo: ask Rich Hickey, or file an issue / pull request

15:29 llasram: Not a pull request

15:30 But yeah, check to see if there's an issue already on the core.async JIRA

15:30 whilo: ok. people seem to be programming fault free, when i am the first to have a problem with this XD

15:30 llasram: That seems like the worst possible behavior for it, short of silently swallowing the exception

15:30 hiredman: whilo: the first thing to do is to see if it is repropducible outside of lein repl, cider, or whatever tools

15:31 whilo: lein test reproduces it as well

15:31 or lein run

15:32 llasram: hiredman: The linked core.async code just calls `println` on any exceptions thrown from async tasks

15:32 So no possibility of stacktraces ever

15:32 hiredman: ah

15:32 well, what should it do?

15:32 llasram: Print a stack trace?

15:32 hiredman: to where?

15:33 llasram: Anywhere :-) I mean, right now it unilaterally prints something useless to *out*

15:33 It seems like an incremental improvement would be to print something useful to *out*

15:33 Then go from there

15:34 hiredman: llasram: I dunno, it seems like there is no best solution, so the best thing is for the user to decide the behaviour they want, and there is a way to do that, put a try/catch in your go expressions that prints a stacktrace

15:34 whilo: printing stacktrace fixes my issue :-)

15:35 hiredman: that didn't work for me

15:35 hiredman: weren't they outside this try-catch block?

15:35 dbasch: hiredman: see the code: https://github.com/clojure/core.async/blob/76b25bf91c670b0c3542ed9cb687ff29fb2183a7/src/main/clojure/clojure/core/async/impl/exec/threadpool.clj#L33

15:35 whilo: much better, now i only feel half blind :-)

15:36 hiredman: dbasch: I see it

15:36 dbasch: no question that printing a stacktrace would be better than .toString

15:36 hiredman: dbasch: but what if I don't want to print the stacktrace

15:37 dbasch: hiredman: what if you don’t want to print .toString?

15:37 same thing

15:37 hiredman: whilo: I doubt that, my guess would be you put the try/catch in the wrong place then

15:37 dbasch: but if you choose one, stacktrace is a more useful default

15:37 hiredman: dbasch: sure, I would argue it should do neither

15:37 dbasch: it looks like the commit that introduced that left debugging printlns in a number of places :/

15:38 llasram: hiredman: Ohhhh, maybe that's what they are. I just noticed that

15:38 There's also this issue http://dev.clojure.org/jira/browse/ASYNC-61 which seems to reflect the behavior prior to that commit

15:40 hiredman: the core.async code seems kind of like the wild west, commits landing that doen't seem to reference issues in jira, debug printlns being left in seems to indicate little or no code review

15:41 dbasch: the comment at the end is right, it seems that the fix was a quick hack

15:41 llasram: hiredman: Which makes me sad :-/

15:42 hiredman: llasram: yep, maybe some day it will settle down, it is still "alpha"

15:42 llasram: And no tbaldridge ATM to grill about it :-)

15:42 hiredman: llasram: I am sure he would point to the aplha designator

15:42 llasram: Probably so

15:43 dbasch: before coding anything, it would be worth thinking about how logging should work for core.async and then implement that

15:44 logging has been one of the most annoying parts of java since forever

15:44 whilo: that indeed was interesting to me as well, as i need to address logging with it soon as well

15:44 hiredman: clojure.tools.logging words fine

15:44 works

15:44 llasram: (inc hiredman)

15:44 lazybot: ⇒ 44

15:45 dbasch: hiredman: but core.async doesn’t use it :)

15:45 hiredman: dbasch: right, logging is your concern as a consumer of core.async

15:46 core.async shouldn't dictate how you do logging

15:48 llasram: Someone needs to create an SLF4J backend for timbre, then the great cycle of JVM logging will be complete

15:50 sveri: Hi, while exploring om I just want to make sure that my thinking is correct. Executing this code: http://pastebin.com/kt5Nes8T it happens that the output "render state" is printed twice to the js console. The first time because the render-state function is called with an unitialized app state and the second time because and the second time because "init-state" of the "text" function was called and changed the application state. This is expec

15:53 ToBeReplaced: llasram: do you use timbre?

15:54 llasram: ToBeReplaced: Nope. tool.logging

15:54 ToBeReplaced: llasram: yeah, same... wondering why someone would use it instead

15:55 llasram: ToBeReplaced: JVM logging is complex enough -- I don't see how adding an entirely new language-specific logging library makes it better

15:56 I've heard people say they couldn't get tools.logging + <Java logging library> configured properly, while timbre is apparently much easier to setup

15:56 And also cite the lack of XML

15:57 OTOH, I just use slfj+log4j w/ the same short ->stderr property file everywhere, so YMMV

15:58 ToBeReplaced: llasram: i guess i can understand that... though that's a little weird b/c if i was starting a project from scratch and thus got to integrate the logging lib of my choice it'd be logback, and not only is their xml config sane, but you can configure it with code instead if you wish

15:59 llasram: idk i shoudl probably stop there... i get a bad taste in my mouth with any of the clojurewerkz libraries, and i already got myself band from one of their repos ;)

15:59 banned*

15:59 llasram: I don't think timbre is ClojureWerkz. Just "supports their goals"

16:00 hiredman: friend of my enemy, etc

16:00 ToBeReplaced: i got bannedd from a taoensso library, heh

16:00 llasram: Ahh

16:00 I was just thinking the Clojure community needed some more drama

16:00 Liven things up a bit

16:01 hiredman: do I want to use a library with goals? what if it doesn't match my lifestyle?

16:02 llasram: What if you grow apart over time, and realize some day that you want to structure your APIs entirely differently?

16:03 hiredman: what if I "link" against the api, but I am not "linking" against the api?

16:04 llasram: You can try spicing things up with a compatibility shim!

16:05 ToBeReplaced: i started putting together a list a while back of clojure libs i'm happy to use/ship, and i found it's actually really small outside of org.clojure

16:05 if either of you (or onlookers) have a similar list i'd be interested in seeing it

16:08 llasram: Hmm, interesting. There's definitely some de facto standard stuff I use everywhere (ring, cheshire), but yeah -- not a lot

16:09 whodidthis: how do i convert these javascript object properties, kind of like arrays, into vectors http://pastebin.com/vdqxdGZx

16:11 llasram: ToBeReplaced: I'm going to chalk it up to the Lisp curse :-)

16:12 ToBeReplaced: llasram: as a non-web developer, my forays into web development on clojure have been pretty rocky -- i found that the middleware abstraction makes it awfully hard to follow RFC 2616; is that false? does it matter?

16:12 amalloy: what does it even mean to be banned from a repo, ToBeReplaced?

16:13 ToBeReplaced: as basic example -- distinguishing between 405 and 404 using a clojure routing solution seems to be tricky

16:13 llasram: ToBeReplaced: I'm the wrong person to ask. We write a lot of internal JSON APIs, but nothing that needs to play nicely with a very wide world

16:13 ToBeReplaced: amalloy: when i try to post comments in issues i get informed i've been blocked from the repository

16:13 amalloy: huh. i didn't even know that was possible

16:14 brb gonna ban some folks from my repos, for science

16:14 llasram: SWEET

16:14 verma: when I am developing stuff using composure I want to refer to a different template instead of the one I use for production (basically the template name that goes into my render call), how can I detect if I am in dev or prod mode during runtime?

16:14 dbasch: whodidthis: https://github.com/clojure/clojurescript/blob/master/src/cljs/cljs/core.cljs#L7356

16:15 ToBeReplaced: verma: consider using JVM options and accessing via System/getProperty

16:15 amalloy: huh. i can't find that option. i wonder if they asked github support specially

16:15 llasram: verma: Alternatively, consider passing in different arguments the function constructing your handler chain for "dev" vs "production"

16:16 My experience is that trying to have stuff which automatically acts differently based on different "environments" creates a lot of hassle

16:16 Especially e.g. around running "test" tests within your "dev" REPL

16:18 ToBeReplaced: amalloy: https://help.github.com/articles/blocking-a-user

16:18 verma: ToBeReplaced, llasram, got it, thanks :)

16:18 coventry`: verma: You might find carica useful for distinguishing dev from production. Environment variables and System/getenv work too.

16:19 llasram: Stops them from forking? Wow

16:19 amalloy: llasram: well, with a fork of a repo you can make yourself a bit of a nuisance

16:19 llasram: How so?

16:19 verma: coventry`, thanks, I think I will go the system env route I think

16:19 amalloy: eg, commit a hundred things that say: "Fixes #121. Repo owner is a nazi."

16:20 those show up in the discussion thread of #121 in the base repo

16:20 llasram: Oh, geez. I didn't realize that

16:20 ToBeReplaced: verma: llasram's take is better/more correct... generally pass things as arguments, i use jvm-opts as the outside configuration that can't be known (ex. "where is logging gonna go?)

16:20 amalloy: but of course you can still clone the repo and re-push it as your own. the code is still shared, you're just not socially connected to upstream

16:20 llasram: Sure

16:21 whodidthis: dbasch: returns the object :( maybe ill figure out something else

16:21 llasram: Oh, humans

16:36 verma: ToBeReplaced, hmmm, sounds good, taking a look

16:37 ToBeReplaced, nice, so jvm-opts are supplied to jvm that lein run uses, but won't be there when I create and distribute my standalone jar, nice

16:39 justin_smith: you can't specify jvm opts in a jar, it simply doesn't work that way

16:40 verma: justin_smith, yeah I know, what I meant was that they will be absent

16:40 justin_smith: I wasn't sure if you were being sarcastic

16:41 verma: :)

16:41 `szx: with datomic, does it make sense at all to add attributes on the fly (i.e. user-generated attributes, over the lifetime of an application) or is that something you're not supposed to do?

16:42 i guess #datomic would be a better place to ask

16:42 heh

16:42 verma: justing_smith, don't think I was being sarcastic, may be not a very coherent thought on my part :)

17:02 DomKM: Is there a protocol for clojure.core/contains?

17:04 amalloy: DomKM: an interface

17:04 should be clojure.lang.ILookup iirc

17:04 DomKM: thanks amalloy

17:09 Krajsnick: Could someone explain me how the different Clojure fib functions I try and time with clojures time function runs a fib(45) on 0.2 msec while node.js does it in 16 secs, and ruby... dont even wanna start a fib(45)

17:09 How can the Clojure fib function be so fast?

17:09 ivan: fibonacci can be computed sequentially

17:10 justin_smith: yeah, it's probably using the memoizing algorithm

17:10 Krajsnick: one of the ones I tried used a memoizing function yes

17:11 So basically the other language just does it linnear, while clojure kinds of jump from one fib number to the next fib to the next

17:12 justin_smith: do you have links to the various implementations?

17:12 Krajsnick: sure

17:12 http://stackoverflow.com/questions/8939970/a-recursive-fibonacci-function-in-clojure

17:12 I used a couple of these

17:12 all of them gives me answer instantly

17:13 now I found one that doesn't, and was 2-3 seconds slower than node

17:13 http://intothewebs.tumblr.com/post/45073028163/a-little-bit-of-clojure the first fib function

17:20 justin_smith: yeah, that one is not memoizing, and also not tail recursive

17:25 perses: is there anybody using titanum graph lib?

17:41 justin_smith: perses: I've been meaning to try it out

17:42 DomKM: amalloy: How would you create a type that implements clojure.core/contains? It looks like ILookup is for clojure.core/get

17:42 justin_smith: DomKM: I think if you implement ILookup you get bot get and contains?

17:43 since get also needs to know whether a value is present or not

17:43 DomKM: java.lang.IllegalArgumentException: contains? not supported on type:

17:43 but get works fine

17:43 coventry: What's a clean way to express a test.check generator which just returns the values from a zero-arity function? I'm looking for something like (gen/fmap (fn [_] (my-fn)) gen/int).

17:43 justin_smith: DomKM: OH, I don't know then

17:44 reiddraper: coventry: hmm, is this a pure function?

17:44 amalloy: yeah, apparently contains? is a bit weird

17:45 you need to implement one of: Associative, IPersistentSet, Set, or Map

17:45 which doesn't seem very nice to me

17:45 reiddraper: coventry: you can use gen/return to create a 'constantly' generator

17:46 coventry: reiddraper: No, I'm trying to generate objects with a lot of shared structure, and my-fn will be pulling objects to be reused from a set in an atom.

17:46 reiddraper: coventry: so will that be adding randomness that is not controlled by test.check?

17:46 coventry: if so, I would recommend against that if possible

17:47 DomKM: amalloy: Set makes sense for my use case. Do you know the protocol/interface for it?

17:47 amalloy: i listed the names of all the interfaces just above

17:47 java.util.Set, or clojure.lang.IPersistentSet

17:48 coventry: reiddraper: That was the idea, though I'm open to suggestions for other ways to construct objects with lots of structural sharing.

17:48 Ah, you don't want to add extra randomness because it breaks shrinking, I guess?

17:48 amalloy: coventry: what about a vector that contains all the objects you want to share, and use like one-of to choose from its items?

17:49 DomKM: thanks

17:49 reiddraper: coventry: what's wrong with creating generators the 'normal' way?

17:49 i'm not sure i follow how structural sharing is relevant here

17:50 coventry: I want to make tests for an object serializer which is aware of structural sharing.

17:51 reiddraper: so, if you serialize X, and then later serialize Y, which shares some structure, it has some different behavior than normal serialization would?

17:52 coventry: reiddraper: No, I want the serialization of [X X X X] to only contain one serialization of X.

17:53 reiddraper: and right now you verify that across different test runs? Or within a single test?

17:53 coventry: (This is for cljs, BTW. I imagine there's already an option for this in java.)

17:54 reiddraper: coventry: from what i've heard so far this wouldn't be easier/harder in clj/cljs

17:54 coventry: reiddraper: Right now, I only have the most basic test: (let [foo [1 2] bar [1 2] composite [foo bar foo]] (test that serialization only has one copy of foo))

17:56 reiddraper: coventry: I would recommend writing generators that are likely to have quite a bit of duplication/sharing, and then, within a single test run/iteration, check that your property of only representing that object once, works correctly

17:56 that way you don't need to use a stateful atom to 'remember' things across test runs

17:57 coventry: Yes, the shrinking property is worth preserving, thanks for pointing that out.

17:57 reiddraper: and reproducibility

17:58 despite being a 'random' testing tool, test.check has provisions for repeating the exact same random test

17:59 coventry: Hmm, I wouldn't have expected that to be a problem, as long as the state atom is created fresh per-run, and the test runs in a single thread.

18:09 Can I use gen/bind recursively?

18:10 reiddraper: coventry: yes, it's quite common to

18:11 coventry: Great, are there any examples you can easily point me to?

18:16 In a recursive gen/bind, how can I signal that the recursion should stop? The recursive generator at https://github.com/clojure/test.check/blob/master/doc/intro.md#recursive-generators does it with a function which takes a size argument. Is there a way to do a bind which is size-aware?

18:18 akhudek: Regarding om, consider rendering a large vector of items. If you remove one item from the middle and add it back to the end, will om/react rerender the entire list becasue the index of each item has changed?

18:19 coventry: akhudek: Any change to the state will trigger a re-render, but components which have views into specific subtrees via cursors will check whether they should re-render by checking whether their subtrees are (identical?). So it depends on the state data you're passing to your components.

18:20 akhudek: https://github.com/swannodette/om/blob/master/src/om/core.cljs#L239

18:25 perses: justin_smith: still there?

18:25 justin_smith: yes, hi

18:26 perses: justin_smith: hi, so you have tried it yet?

18:26 justin_smith: not really, no - but if you have a problem or question it can't hurt to ask

18:27 perses: justin_smith: how can i add vertex uniquely to the graph?

18:28 if i did (tg/transact! (tv/create! {:name "hello"}) (tv/create! {:name "hello"}) (tv/create! {:name "hello"})), will add 3 vertices

18:28 but the logic is it should be one?

18:28 justin_smith: titanium.clojurewerkz.org/articles/vertices.html unique-upsert looks like it may be the thing?

18:28 yeah, you want the unique-upsert! function for that (it meantions it right after create! in the docs I linked)

18:29 perses: ah so i should replace tv/create! to tv/unique-upsert! ?

18:30 justin_smith: I think so, but only based on reading the docs just now - it may be more complex than that

18:30 can't hurt to try

18:30 oh, upsert needs a location

18:32 coventry: reiddraper: NM, I see how to do it now.

18:32 reiddraper: coventry: cool

18:32 coventry: Thanks for your help.

18:37 akhudek: coventry: Thanks, I get that much, but I’m tyring to debug a performance problem and suspect that it’s actually updating the whole list since I see updateDom as taking the most time in a profile. I’m trying the react dev tools and each item in the list is encolosed in an om wrapper cursor that contains the index in it’s props.

18:40 coventry: akhudek: When I ran into this problem, I was able to verify that suspicion by sticking a (js/console.log (pr-str (element identifier))) in the render method.

18:42 akhudek: Just to be clear, when you say "each item in the list is enclosed in an om wrapper cursor," you mean that the components associated with the list elements get the element data via an om cursor, right?

18:45 akhudek: each component of the list is definitely an om cursor. The structure is a bunch of maps in a large vector. This vector is sorted and then build-all is called on the resulting list. Thus each individual item (a map) should still be a cursor. I can see that in the dev tools clearly. But there is an “unknown” react component around each item that seems to be part of om internals.

18:46 coventry: I just tried the console log trick, and it definitely calls render on each item of the list for every update. It’s unfortunately frozen up now though. There are over 2000 items and I guess the logging could not handle the output.

18:49 coventry: also, calling render doesn’t actually mean that it will update the dom, right? or does it?

18:50 coventry: akhudek: No, my understanding is that the actual dom element will not be updated unless the output of the render method has changed.

18:53 akhudek: However, it is surprising that the render method of the element components are being called at all, since their values should be identiical to their previous values.

18:54 akhudek: coventry: yeah, I didn’t think it should be calling render either.

19:16 coventry: I'm not sure how to go about debugging this test.check generator. It's giving me an NPE with a stack trace which doesn't mention my namespace, and none of my debugging printlns are producing output. Any suggestions? https://www.refheap.com/78021

19:18 dbasch: what’s the best / usual way to tell a cljs app that it’s running in production or dev?

19:19 akhudek: coventry: figured out why it’s calling render at least. The items are = but not identical.

19:20 coventry: akhudek: Oh, it wasn't just a rearrangement of the list? That makes sense.

19:22 dbasch: You can use a macro to do it whatever way you do it in clj, at compile time.

19:27 akhudek: coventry: oh man, implementing a custom should-update that swaps the identical? check for = completely fixed the performance problems.

19:28 coventry: akhudek: Yeah, I had a similar experience.

19:30 akhudek: I’m curious about dnolen_’s thoughts on this.

19:31 coventry: Well, an equality check is expensive. The whole reason om is more performant than react is that it does identity checks.

19:31 dbasch: coventry: In clj I use the jvm environment, but I’ll look into carica

19:32 coventry: dbasch: Not sure why, but wiser people than me were saying earlier that jvm-opts is the way to go.

19:33 dbasch: coventry: ok, but what do you do in the browser?

19:33 dnolen_: akhudek: as a general rule that will slow things down in Om

19:34 akhudek: at least in the current version anyway, working on some things that will allow us to switch to = over identical?

19:34 coventry: dbasch: You make a java macro, which you call at compile time in your clojurescript.

19:34 dbasch: coventry: you mean a clj macro that reads from the jvm environment, I assume

19:35 coventry: dbasch: yeah, like (defmacro prod? [] (System/getenv "PROD"))

19:37 justin_smith: coventry: but that would check whether compilation was happening where PROD is set - it could cause unexpected results with uberjar creation

19:38 if aot is involved, at least

19:38 dbasch: coventry: it would be better to do something with the dev/prod profiles in cljsbuild

19:41 coventry: dbasch: You're right.

19:41 justin_smith: I was just giving an example of how to get something from the outside environment into cljs.

19:41 justin_smith: ahh, ok

19:42 dbasch: coventry: the first thing that occurs to me is to have a different output name and check the running script name, but that’s *really* ugly

19:43 frustration-stat: I am trying to load clojure.tools.cli 0.3.1 in a repl, but no matter which method I use, the version built-in to my clojure version is used, which is older than 0.3.1

19:43 justin_smith: have the app create a file recording its PID and metadata about itself?

19:43 coventry: dbasch: If you want to do that, you can put something like :profiles {:prod {:resource-paths ["config/prod"]} :dev {:resource-paths ["config/dev"]}} in your project.clj, and use carica. (This is what we do, actually.)

19:44 dbasch: coventry: yes, I cannot think of a better option

19:45 frustration-stat: ie: (use '[clojure.tools.cli :as cli :only [parse-opts]]) => IllegalAccessError parse-opts does not exist clojure.core/refer (core.clj:3849)


19:47 dbasch: frustration-stat: what’s your project.clj?

19:48 frustration-stat: dbasch: i've tried with [org.clojure/tools.cli "0.3.1"] in project.clj and i've also tried with lein-try

19:48 same result

19:48 akhudek: dnolen_: I guess our use case is somewhat pathelogically bad for om updates when using identical. We do a fair amount of data manipulation prior to feeding data into components. E.g. for each item in a list, assoc a sublist of related data. This is because our base data is a collection of automatically updated materialized sql queries. We handle one to many or many to many relationships by composing data in the client.

19:49 frustration-stat: dbasch: the only way i've gotten it to work is to clone the github repo and run a lein repl from the checkout

19:49 dnolen_: akhudek: sure, IShouldUpdate is there for a reason

19:50 akhudek: however it important that you understand the default implementation (or copy and paste it and just change the bit you need)

19:50 dbasch: frustration-stat: I just created a blank project with clojure 1.5.1 and it works fine

19:50 frustration-stat: what clojure are you using?

19:51 akhudek: dnolen_: yeah, I’ve copied and modifed the cond here https://github.com/swannodette/om/blob/master/src/om/core.cljs#L239

19:51 frustration-stat: dbasch: i'vew tried both 1.5.1 and 1.6.0

19:51 dbasch: frustration-stat: (same with 1.6.0)

19:51 akhudek: dnolen_: by the way, I did create a set cursor implementation, but sadly found that it doesn’t work well as a backing for stateful compoenents

19:51 dbasch: frustration-stat: there’s probably a dependency conflict, you should post your project.clj or run lein deps :tree

19:52 coventry: akhudek: How does it break?

19:52 dnolen_: akhudek: just note using your should-update breaks om/set-state! for that component for now (I'm assuming your using :ctor option to do this)

19:52 akhudek: care to elaborate on the set cursor? not really following

19:54 frustration-stat: dbasch: i just tried a blank project, must be a conflict, checking :tree, thanks

19:55 akhudek: dnolen_: I found that set-state uses the path to the cursor in it’s call to assoc. This would be fine, but it also seems to represent state using a copy of the data? In any case, I ended up getting errors because you cannot assoc through a set.

19:55 hold on and I’ll link the implemenation, it’s just a small modification to mapcursor

19:56 https://github.com/akhudek/om/blob/set-cursor/src/om/core.cljs#L415

19:56 Also modified to-cursor to be aware of sets.

19:56 other than the state, it seems to work

20:00 dnolen_: akhudek: yeah another issue that will be solved by what I'm working on

20:02 akhudek: dnolen_: ok, sounds good. Is there documentation for the :ctor option you mentioned above? I’m not familiar with it.

20:02 dnolen_: akhudek: you can supply an alternative backing React component, an alternative to pure

20:02 coventry: ,(let [len 1e7 a (doall (range len)) b (doall (range len))] (time (= a b)))

20:02 clojurebot: #<OutOfMemoryError java.lang.OutOfMemoryError: Java heap space>

20:03 coventry: ,(let [len 1e5 a (doall (range len)) b (doall (range len))] (time (= a b)))

20:03 clojurebot: "Elapsed time: 65.673784 msecs"\ntrue

20:03 coventry: (let [len 1e5 a (range len) b (range len)] (time (= a b)))

20:03 ,(let [len 1e5 a (range len) b (range len)] (time (= a b)))

20:03 clojurebot: "Elapsed time: 68.550158 msecs"\ntrue

20:04 dnolen_: akhudek: it's documented in build's docstring but there's not an example yet beyond the `harmful` example in the repo

20:04 coventry: Why does this equality check take almost the same time whether or not I force the structures with doall before the clock starts?

20:05 (With length 1e7 on a real machine, doall only knocks off about 20% of the time)

20:05 dnolen_: coventry: ranges aren't lazy seqs

20:05 akhudek: dnolen_: ok, thanks, I’ll read up on that

20:07 coventry: ,(class (range 10))

20:07 clojurebot: clojure.lang.LazySeq

20:09 dnolen_: coventry: oh hmm, perhaps getting confused because there's a Range.java and Range deftype in ClojureScript

20:13 Bronsa: dnolen_: looks like clojure's range uses chunked buffers

20:13 dnolen_: Bronsa: yeah

20:14 Bronsa: Range.java looks exactly like cljs Range OTOH

20:15 dnolen_: Bronsa: yeah chunked buffers came late to ClojureScript

20:15 coventry: Even with chunking, I would have expected the object creation to be more expensive than the equality check. Am I just wrong about that?

20:58 amalloy: coventry: i would expect that too, but i could imagine it being wrong. object allocation and arithmetic are both very cheap, and perhaps equality is expensive because it has to double-check types over and over. have you tried in a more careful benchmark, eg via criterium?

21:00 coventry: No, that's a good idea, although I actually came across this in cljs, and that's where I'm really interested in the question. Not sure whether you need to take the same care when benchmarking javascript, have to do a bit of research.

21:09 amalloy: you need to take care when benchmarking anything. small sample sizes in unrealistic situations don't tell the real story

21:09 TravisD: I am really not trying to troll. Is there a performance improvement to using scala over clojure?

21:13 kras: came up with the following code for my own version of flatten https://www.refheap.com/78032

21:13 I am trying to make it do lazy eval

21:14 coventry: amalloy: Thanks, it looks like the answer is "use jsperf.com". Sounds easy...

21:14 kras: looks like the trail and error method of inserting lazy-seq on recursion calls is not helping

21:14 any suggestions?

21:15 coventry: Maybe http://clojuredocs.org/clojure_core/1.2.0/clojure.core/lazy-cat ?

21:16 jdkealy: I've been confused with compojure and jetty. I don't know how to get this :title attribute from a request payload. I have added wrap-params to my routes... Additionally, when I try this route, it seems i need to restart my server to see any changes take effect. https://gist.github.com/jdkealy/11129546

21:18 amalloy: yeah, instead of into, just use concat

21:18 and wrap the whole thing in a lazy-seq

21:19 kras: ,(concat ["a"] ["b"])

21:19 clojurebot: ("a" "b")

21:19 ivan: is there a try/catch/else macro somewhere?

21:19 kras: amalloy: coventry: thanks for the clue

21:20 amalloy: ivan: what would the else do?

21:20 ivan: amalloy: run something if no exception was caught

21:21 amalloy: that's just...more stuff after the try

21:21 (try (a) (b) (catch))

21:21 unless you really really don't want to catch them in b, i guess

21:21 ivan: no, because then the catch covers (b)

21:21 right

21:21 Python has this :)

21:22 kras: hurray, (take 5 (flt (range))) works now with stackoverflow :-)

21:23 I meant without*

21:24 * ivan finds a discussion of the else thing in http://clojure-log.n01se.net/date/2013-05-10.html

21:26 coventry: I've got a generator which produces deeply nested structures with extensive structural sharing, but it's awfully slow... any suggestions for ways to speed it up? https://www.refheap.com/78033

21:27 (Response when I mixed that message to ##javascript: "<j201> THE PARENS THEY BURN")

21:29 kras: any suggestions on whom to follow on 4clojure's solutions list

21:29 coventry: daowen is the shit.

21:32 ivan: I feel like Clojure code could use some vertical whitespace outside of cond

21:33 kras: coventry: real cool man, he just did it in one line and its more readable

21:33 thanks for the suggestion

21:33 justin_smith: ivan: -> / ->> lead to good vertical whitespace

21:34 ivan: it does? my imagination is failing me

21:34 justin_smith: wait, I could be misunderstanding you

21:34 clojurebot: Gabh mo leithscéal?

21:35 justin_smith: how does cond lead to good vertical whitespace?

21:35 Frozenlock: coventry: I feel the lack of parens disturbing. It's like driving at high speed without a seat belt.

21:36 er.. "the lack of parens is disturbing"

21:36 ivan: justin_smith: blank lines between things

21:37 justin_smith: ivan: blank lines within a form is not good style as far as I am concerned, but you can put in line breaks anywhere you want

21:39 I have a coworker who pretty much puts empty lines in his defns whereever

21:39 it kind of breaks how I use emacs though

21:41 fuJiin: noob question - anybody building webapps use futures for parallel db calls?

21:42 anything to watch out for when doing this?

21:42 justin_smith: it may not help much if the parallel calls are to the same db

21:43 coventry: justin_smith: How does that break emacs?

21:44 justin_smith: it breaks the "defun is separated by blank lines" assumption used by many of my favorite keybindings

21:44 kras: how do I know if a function evals lazily?

21:44 fuJiin: its the same db, but so far its shaved a full second off response times

21:44 justin_smith: coventry: not "break" really as much as make them not be as useful

21:44 coventry: Oh, OK.

21:44 kras: the mapcat function doc doesn't say anything about laziness but looks like it evals lazily

21:45 justin_smith: kras: the way to check is the type of the output

21:45 ,(class (mapcat identity (range)))

21:45 clojurebot: clojure.lang.LazySeq

21:45 justin_smith: that's how you know

21:46 kras: justin_smith: thank you

22:17 I have written my own version of max as https://www.refheap.com/78039

22:17 this works fine in my repl

22:17 but gives an error on 4clojure

22:18 clojure.lang.ArityException: Wrong number of args (1) passed to: core$partial

22:27 danlamanna: can anyone tell me why the first works and the second doesn't? https://gist.github.com/danlamanna/11130607

22:28 owl-v-: does .isFile returns boolean?

22:29 `szx: danlamanna: because it's a java method, not a function?

22:29 ,(doc memfn)

22:29 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."

22:29 `szx: danlamanna: ^

22:29 danlamanna: ahh

22:31 Bronsa: danlamanna: methods are not first-class like functions, you have to wrap method calls in fns if you need to use them as such.

22:31 owl-v-: (not= (filter (method) (stuff)) (filter (boolean) (stuff)) )

22:31 dbasch: danlamanna: you can wrap it like this: #(.isFile %)

22:36 justin_smith: it appears kras left (if you renamed I don't see those messages right now), the problem with mymax is that (partial mymax) should be #(partial mymax %&)

22:38 but really if you are using reduce already there is only need for the one and two arg versions (as a helper fn) plus a wrapper to do the reduce

22:46 owl-v-: is (defn fun [] (fun)) same as (defn fun [] (recur)) ???

22:46 lazybot: owl-v-: How could that be wrong?

22:47 justin_smith: owl-v-: there is no such thing as implicit tail recursion in clojure

22:47 so they are not the same

22:47 *implicit tail recursion optimization

22:49 owl-v-: (defn fun [] (fun)) < (defn fun [] (recur)) ???

22:49 lazybot: owl-v-: How could that be wrong?

22:49 owl-v-: lol. lazybot~

22:49 justin_smith: well the latter is optimized

22:49 usually you want that

22:52 owl-v-: justin_smith: thanks

22:53 bbloom: apparently three question marks is wildly inappropriate conduct, says lazybot ???

22:53 lazybot: bbloom: Yes, 100% for sure.

22:53 bbloom: (inc lazybot)

22:53 lazybot: ⇒ 25

22:53 justin_smith: what about 4 question marks ????

22:53 hmm ???

22:53 lazybot: justin_smith: Oh, absolutely.

22:54 bbloom: or an interrobang ‽

22:54 owl-v-: what does '???' do ???

22:54 lazybot: owl-v-: Oh, absolutely.

22:54 bbloom: it does stuff ‽‽‽

22:54 agarman: ,(apply str (repeat 3 \?)))

22:54 clojurebot: "???"

22:55 bbloom: agarman: the bots ignore each other

22:55 ,(println "???")

22:55 clojurebot: ???\n

22:55 bbloom: ,(print "???")

22:55 clojurebot: ???

22:55 bbloom: ???

22:55 lazybot: bbloom: Yes, 100% for sure.

22:56 owl-v-: lazybot accepts only user message ???

22:56 lazybot: owl-v-: How could that be wrong?

22:58 schlegel: ???

22:58 lazybot: schlegel: Oh, absolutely.

22:58 schlegel: What's the point

22:58 owl-v-: ,(prn "yes ???")

22:58 clojurebot: "yes ???"\n

22:58 owl-v-: ,(print "yes ???")

22:58 clojurebot: yes ???

22:58 justin_smith: ,'???

22:59 clojurebot: ???

22:59 lazybot: justin_smith: How could that be wrong?

22:59 owl-v-: justin_smith: u did it!

22:59 schlegel: No it replied to him

23:00 justin_smith: ,(:q '{:q ??? :a !!!})

23:00 clojurebot: ???

23:00 owl-v-: ,'final boss ???

23:00 clojurebot: final

23:00 lazybot: owl-v-: Oh, absolutely.

23:00 owl-v-: oh

23:01 ,(print "/NICK clojurebot2")

23:01 clojurebot: /NICK clojurebot2

23:02 owl-v-: ,(print "???")

23:02 clojurebot: ???

23:02 owl-v-: bot can't change nickname???

23:02 lazybot: owl-v-: How could that be wrong?

23:04 owl-v-: ,(print owl-v-)

23:04 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: owl-v- in this context, compiling:(NO_SOURCE_PATH:0:0)>

23:04 justin_smith: /<command> is a client binding IIRC - "/nick" would only work if clojurebot were using a client that recognizes that as a command to send a nick message

23:05 owl-v-: ah...

23:05 justin_smith: but he uses a clojure lib with bindings on a lib level to send commands - his stream isn't parsed for commands

23:05 I think

23:06 for a while I used a vi-like client where the used :command

23:07 owl-v-: ,(clojurebot)

23:07 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: clojurebot in this context, compiling:(NO_SOURCE_PATH:0:0)>

23:07 owl-v-: ,(lazybot)

23:07 clojurebot: #<CompilerException java.lang.RuntimeException: Unable to resolve symbol: lazybot in this context, compiling:(NO_SOURCE_PATH:0:0)>

23:08 owl-v-: (inc lazybot)

23:08 lazybot: ⇒ 26

23:08 owl-v-: (inc lazybot)

23:08 lazybot: ⇒ 27

23:08 owl-v-: why is it increasing ?

23:09 (dec lazybot)

23:09 lazybot: ⇒ 26

23:09 owl-v-: (class lazybot)

23:10 TEttinger: (inc knowledge)

23:10 lazybot: ⇒ 1

23:10 TEttinger: inc is increment and is, if you omit the , or & to evaluate, a special call to the bot

23:10 justin_smith: (inc is just a command, not part of the clojure interpreter

23:11 TEttinger: basically (inc blah) is a special thing these bots do, that also can't do real evaluation

23:11 justin_smith: $karma knowledge

23:11 lazybot: knowledge has karma 1.

23:11 TEttinger: (inc (str "T" "Ettinger"))

23:11 lazybot: ⇒ 1

23:11 TEttinger: $karma TEttinger

23:11 lazybot: TEttinger has karma 15.

23:11 justin_smith: $karma (str

23:11 lazybot: (str has karma 0.

23:12 justin_smith: $karma (str "T" "Ettinger")

23:12 lazybot: (str has karma 0.

23:12 TEttinger: ha

23:12 justin_smith: (inc (str "lorem" "ipsum"))

23:12 lazybot: ⇒ 1

23:13 justin_smith: (karma (str "lorem" "ipsum"))

23:13 $karma (str "lorem" "ipsum")

23:13 lazybot: (str has karma 0.

23:13 justin_smith: (inc (str)

23:13 lazybot: ⇒ 1

23:13 justin_smith: $karma (str "lorem" "ipsum")

23:13 lazybot: (str has karma 1.

23:14 justin_smith: silliness

23:17 yedi: anyone have experience with environ?

23:18 whenever I access a key from `env` it seems to blow away my .lein-env file (aka replace the contents of the file with an empty map)

23:24 rberdeen: is the second (:require) form from http://dev.clojure.org/jira/browse/CLJS-721 supposed to work?

23:24 (:require [baz.woz :as woz :refer [one] :refer-macros [two])

23:26 ah, it's http://dev.clojure.org/jira/browse/CLJS-785

23:28 yedi: regarding environ: degrading to 0.4.0 seemed to fix my problem

23:47 how exactly do the cljsbuild ids work?

23:48 om has different cljs build settings for dev and prod, and it's managed by ids. how would I go about creating an uberjar with the specific set of build settings i want?

Logging service provided by n01se.net