#clojure log - Nov 15 2014

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

0:56 nonuby: if I have a map with deep nested maps etc. and I want to perform a mutation of specific values (mainly convert those of a particular type to str) would clojure.walk/walk be the best place to start?

0:58 justin_smith: nonuby: do you want to do it based on type, or based on where they are in a map?

0:58 also, maps aren't mutable, you would be making a modified copy regardless

0:58 nonuby: purely based on type, disregard of where/depth they are in the map

0:59 justin_smith: than yeah, walk/postwalk is usually the right thing

1:00 ,(walk/postwalk (fn [e] (if (string? e) (keyword e) e)) {"hello" ["world" {:foo '(bar "baz")}]})

1:00 clojurebot: #<CompilerException java.lang.RuntimeException: No such namespace: walk, compiling:(NO_SOURCE_PATH:0:0)>

1:00 justin_smith: ,(require '[clojure.walk :as walk])

1:00 clojurebot: #<SecurityException java.lang.SecurityException: denied>

1:00 justin_smith: &(require '[clojure.walk :as walk])

1:00 lazybot: ⇒ nil

1:00 justin_smith: &(walk/postwalk (fn [e] (if (string? e) (keyword e) e)) {"hello" ["world" {:foo '(bar "baz")}]})

1:00 lazybot: ⇒ {:hello [:world {:foo (bar :baz)}]}

1:03 nonuby: thanks

1:04 justin_smith: &(walk/keywordize-keys {"foo" :bar "baz" ["quux"]}) ; related but different

1:04 lazybot: ⇒ {:foo :bar, :baz ["quux"]}

1:48 liathit: What is "?" in clojure? Example: (defn foo? [])

1:49 justin_smith: liathit: it is a part of a name like any other character

1:49 ,(defn foo? [] 1)

1:49 clojurebot: #'sandbox/foo?

1:49 justin_smith: ,(foo?)

1:49 clojurebot: 1

1:49 justin_smith: usually it means a function that returns true or false, but that's just a convention

1:50 liathit: there are a few special symbols that modify words in clojure, but that's at the beginning 'quote #reader-macro :keyword etc.

1:50 @deref

1:51 &(->> 'clojure.core ns-publics keys (map name) (filter #(.endsWith % "?")))

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

1:52 justin_smith: oh yeah, lazybot doesn't like that

1:52 &(->> 'clojure.core ns-publics keys (map name) (filter #(.endsWith % "?")) (clojure.string/join " "))

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

1:52 justin_smith: ,(->> 'clojure.core ns-publics keys (map name) (filter #(.endsWith % "?")) (clojure.string/join " "))

1:52 clojurebot: "decimal? contains? every? satisfies? seq? fn? vector? thread-bound? isa? char? some? future-done? pos? sequential? neg? reduced? float? set? reversible? bound? map? volatile? var? empty? string? associative? keyword? even? extends? counted? future? zero? not-every? class? future-cancelled? sorted? nil? instance? record? identical? true? integer? special-symbol? ratio? delay? ifn? chunked-seq? dis...

1:56 liathit: Thank you for the help

1:59 lazybot: (+ 1 1)

2:01 amalloy: &(+ 1 1)

2:01 lazybot: ⇒ 2

2:01 liathit: &(+ 1 1)

2:01 lazybot: ⇒ 2

2:01 liathit: amalloy: :)

3:06 zerkms: Hey there. Guys, what would be an idiomatic here instead of ugly `if`? https://www.refheap.com/93405

3:06 what I don't like is that "offset" there is repeated 4 times

3:12 kenrestivo: is there a good way to represent a circular data structure in clojure? i.e. 1->2->3->4->1 ?

3:14 TEttinger: (doto rac (.seek (if (>= (.length rac) offset) offset 0))) ;there, now it's only repeated 3 times

3:16 kenrestivo: hmm, maybe i just just use CircularArrayList or similar in java

3:16 zerkms: kenrestivo: http://clojuredocs.org/clojure.core/cycle may be

3:16 TEttinger: would you do it like that? Now it's hard to read

3:17 kenrestivo: cycle is cool if i want to turn a circle into a line (sequence). i'm looking to take points and place them on a circle, and be able to determine if they are left or right of each other

3:18 TEttinger: I mean, maybe the simplest thing to do would be to not reuse names for different immutable values

3:18 kenrestivo: kind of thing i'd do with linked lists in c, i guess

3:18 TEttinger: let [offset-revised (if (>= (.length rac) offset) offset 0)] ...

3:18 that might make it a bit more clear

3:19 zerkms: "that might make it a bit more clear" --- that's very true indeed

3:20 TEttinger: I don't think if is a terrible thing to use in clojure

3:35 kenrestivo: ah, nevermind, i just used maps and immutability. https://www.refheap.com/93408

3:37 zerkms: kenrestivo: learnt about "condp

3:37 " from it

3:53 olivierrr: (= (repeat 100 :foo) (take 100 (iterate ___ :foo))))

3:53 i'm stuck on that koan, any hint would be appreciated :)

3:54 kenrestivo: haha

3:54 godd2: olivierrr what function returns the argument passed to it?

3:55 olivierrr: (if true :foo) ?

3:55 or (map) perhaps?

3:55 kenrestivo: simpler than that

3:56 more boring.

3:57 it's a function that, looking at it, you'd think "why would anyone ever want to use that?"

3:58 olivierrr: (fn :foo) ?

3:58 i have no idea

3:59 kenrestivo: i'd have a look through the list of functions here: http://clojuredocs.org/quickref/Clojure%20Core

4:00 godd2: olivierrr consider the math function f(x) = x

4:00 what is f(3) ?

4:01 olivierrr: 3

4:02 return args[0]

4:02 godd2: alright so you agree that f(x) = x returns whatever was given to it, correct?

4:02 olivierrr: right

4:02 godd2: well in math, this is called the "identity" function

4:03 in other words, the input and output are identical

4:04 in clojure, there is a function of the same name

4:04 kenrestivo: and you can write your own by translating godd2's math into clojure, i.e. f(x)=x

4:04 godd2: https://clojuredocs.org/clojure.core/identity

4:04 olivierrr: got it, thanks godd2

4:04 thanks kenrestivo

4:04 kenrestivo: basically, (fn [x] x)

4:06 olivierrr: very cool, thanks again :)

4:32 Glenjamin: I just thought of a great plugin name, but I don't have a plugin to use it

4:32 So I'm throwing it out there; lein-backer

4:57 zerkms: Guys, would you say that (do (async/close! stop) (async/close! out)) works the same as (map async/close! [stop out]) (apart of returning result, which I don't care)

4:57 ?

5:02 kungi: zerkms: it might create a problem with map being lazy

5:03 zerkms: kungi: I see, it makes sense

5:03 kungi: zerkms: I think the if you want to shorten this you should use doseq instead of map

5:03 zerkms: doseq is used for the sideeffects

5:03 zerkms: yep, it explains everything, thanks

5:04 kungi: zerkms: did the channels not close properly with the map solution

5:04 ?

5:04 zerkms: that's correct

5:04 they didn't

5:04 kungi: I've seen this in my code when I used for

5:07 zerkms: Implemented it as (doall (map async/close! [stop out])) which looks slightly better whan doseq in this case

5:07 kungi: ^ ^

5:11 kungi: (doseq [c [stop out]] (async/close! c))

5:12 Either way seems nice :-)

5:12 zerkms: seems like it's very personal :-) may be I'm map-liker

5:16 justin_smith: zerkms: when you don't care about the result, use dorun instead of doall

5:17 zerkms: because... ?

5:17 justin_smith: because doall holds onto the result data structure, and dorun throws away the results

5:17 better memory performance

5:17 zerkms: yep, checked docs

5:17 thanks

5:18 justin_smith: for two items it doesn't matter much

5:18 but it's good to get in the habbit of using the right one

5:18 zerkms: yep, it makes sense as well

5:19 justin_smith: also, if the input is the classic Soul get The Crystals, one should use the-do-ron-ron

5:20 zerkms: :-S

5:20 the last phrase is over my english-fu

5:20 justin_smith: sorry - it's a joke

5:20 zerkms: yep, I got it's a joke, just didn't get it :-)

5:21 justin_smith: The Crystals are known for the song https://www.youtube.com/watch?v=cSpwxz8s0NU

5:21 zerkms: btw, https://www.refheap.com/93411 --- my precious

5:21 1 day of crafting it. 2 days of programming in clojure in total

5:24 justin_smith: zerkms: for two days of clojure experience, that's damn good

5:25 zerkms: I've been reading a lot for a long

5:25 It probably was a year of lazy-reading without a single line written :-D

5:52 cfleming: I agree, looks very good. Nice work zerkms!

5:54 zerkms: It actually now looks even better with moving an alts!! duplicate to its own function: https://www.refheap.com/93412

5:54 btw, thanks :-)

5:58 what you guys use for clojure? trying la clojure with idea, but it seems like it's missing some useful features

5:59 justin_smith: zerkms: funny you should ask about idea.. cfleming writes cursive, which is very popular, probably the best integration right now

5:59 I use emacs, because I have always used emacs

5:59 zerkms: justin_smith: several weeks ago it was a local meetup with a guy who develops Cursive

6:00 I couldn't get there :-(

6:00 cfleming: zerkms: I'm biased, but I think you should definitely use Cursive over La Clojure - LC is basically deprecated now in favour of Cursive

6:00 zerkms: Are you in Wellington?

6:00 zerkms: yep

6:00 cfleming: zerkms: Nice, I'm just across the water in Nelson

6:00 zerkms: how was it? :-)

6:00 oh, lol

6:01 cfleming: It was cool, it was the second meetup and got a lot more people than the first, so hopefully there's a community forming there.

6:01 zerkms: I rsvp'd for next with hope that I will be able to do it

6:02 cfleming: Mostly Scala programmers but there's one company doing only Clojure/ClojureScript, and one company just putting Datomic into prod

6:02 zerkms: curious how long it will take for seek/trademe jobs for the first clojure position in NZ

6:02 really? that's surprising to hear

6:02 cfleming: There are a few companies using it here now.

6:03 But a lot more Scala

6:03 justin_smith: Where are you based? I'm starting to wonder if you ever sleep.

6:03 justin_smith: cfleming: having some insomnia tonight

6:03 west coast US

6:04 cfleming: justin_smith: Ah, ok.

6:04 justin_smith: I usually wake up pretty early, (like 5 am or so) but if I do anything social I end up staying up late...

6:04 so there are few hours I am never up :)

6:04 cfleming: Hehe, yeah, I'll just never see them from here :)

6:07 justin_smith: this is compounded by heavy caffiene usage interspersed with caffeine withdrawal (to reduce the dependency which limits the effectiveness of caffeine) so some days I rarely sleep, others I am rarely awake..

6:08 cfleming: justin_smith: I gave up coffee a couple of years back when I was having a pretty stressful time and it was making me anxious. I was amazed how much better I slept, I never thought it affected me.

6:09 justin_smith: cfleming: yeah, I am dependent on that chemical control of productivity - though I would like to rely on self-discipline instead, working on that

6:29 TEttinger: justin_smith: long-acting stimulants like vyvanse can do the same thing caffeine does with a lower risk of dependency or tolerance and no crash

6:29 vyvanse is a controlled prescription med here in the US

6:30 relative of adderall, just longer lasting and harder to abuse (by design)

6:32 I've gone from maybe 4 no-doz-equivalent caffeine pills a day to, most days, a half of a caffeine pill after the "baby dose" of vyvanse wears off by the evening.

6:32 800mg caffeine to 100mg is a big help :)

7:08 Xack: hi, is it possible to specify a pure Java class as :main for leinengen?

7:12 i need to do this because of https://github.com/libgdx/packr/issues/33

7:32 gfredericks: Xack: what's the goal there? to make it your startup class in an uberjar?

7:33 Xack: gfredericks: yes

7:34 the packr utility (as linked above) doesn't seem to want to play well with play-clj, and i'm trying to make leiningen use a standard Java class, however, it wants to look for "-main", which AFAIk I can't do, and leads to syntax errors

7:35 i would like it to use the "main" function, if possible

7:35 if it isn't, i have no idea what else to do :(

7:35 gfredericks: but an uberjar is your only use case for this?

7:35 Xack: well, not really, lein run also

7:36 an uberjar is used in order for packr to work "properly"

7:36 IIRC uberjar packs clojure with itself, is that correct?

7:36 very new to this :P

7:36 gfredericks: yes

7:36 lein run can take a class already I think

7:36 Xack: gfredericks: moment

7:37 gfredericks: try `lein run -m My.Class`

7:38 Xack: Exception in thread "main" java.lang.IllegalStateException: Attempting to call unbound fn: #'crateincinerator.core.desktop-launcher/-main, compiling:(/tmp/form-init2641406317692387679.clj:1:72)

7:39 gfredericks: leininegen wants a function called "-main", apparently

7:39 oh.

7:39 yep, i derped

7:39 one sec

7:42 heh, if i read it correctly (the full stacktrace), it told me that the java wrapper was actually being run, and that it was an error in the java wrapper code

7:42 thanks!

7:45 gfredericks: np

7:46 wrt the uberjar, I didn't have a lot of luck checking the leiningen source. It looks like the `jar` task can take a main argument, but I'm not sure how to get the rest of the uberjar functionality back if you do that

8:05 nonuby: since there is no mapcat-indexed (i require the idx as part of map op) is it better to do (filter identity (map-indexed map-op coll)) or (concat (map-indexed (fn [idx i] (if (map-op idx i) [i] []))) coll)?

8:07 hyPiRion: (for [[idx i] (map list (range) coll) :when (map-op idx i)] i) perhaps?

8:07 I feel it reads better at least

8:15 nonuby: nice

9:03 m1dnight_: is there a thing such as a namespace bound variable? So that every thread/namespace that calls a function in namespace X can access it?

9:05 Bronsa: m1dnight_: if you fully namespace qualify a symbol and the namespace is loaded, the var is accessible everywhere

9:05 e.g. clojure.string/join

9:05 m1dnight_: yeah, but I'm talking about an atom, for example

9:06 I'm going to try it

9:06 that might be best :p

9:06 Bronsa: you still have to hold an atom in a var

9:23 gfredericks: ,(def obj (atom (ref (agent (future (promise))))))

9:23 clojurebot: #<CompilerException java.lang.SecurityException: no threads please, compiling:(NO_SOURCE_FILE:0:0)>

9:23 gfredericks: ,(def obj (atom (ref (agent (promise)))))

9:23 clojurebot: #'sandbox/obj

9:23 gfredericks: ,obj

9:23 clojurebot: #<Atom@ce4dda: #<Ref@123a08e: #<Agent@2fcb4f: #<core$promise$reify__6499@25a311: :pending>>>>

9:32 martinklepsch: can someone point me to good examples of https://github.com/stuartsierra/component in use?

9:35 m1dnight_: "Attempting to call unbound fn: #'clojure.core/unquote""

9:35 but my source runs fine on my laptop

9:35 sems like core is not loaded, or what?

9:35 Bronsa: ,~1

9:35 clojurebot: #<IllegalStateException java.lang.IllegalStateException: Attempting to call unbound fn: #'clojure.core/unquote>

9:36 m1dnight_: but, it compiles/runs fine on my laptop? :p it's the exact same source

9:36 i tried lein clean, lein deps and lein run

9:36 nothing works

9:36 Bronsa: it must be hitting a different code path for some reason

9:36 look for unquotes outside syntax-quote

9:38 m1dnight_: it points me to a line where I have `(let ~letbinds ~condody)

9:38 seems to be fine to me

9:39 Bronsa: maybe the value of letbinds or condody has contains an unquote, I can't really help you without the code

9:39 m1dnight_: mmm

9:39 it's really weird, I pushed/pulled again, but seems to be broken

9:39 ill just work on my laptop I guess

9:42 aha!

9:42 i forgot to lein clean on laptop

9:42 I'd set the status of my problem to solved but that'd be non-idiomatic so i'll create a new problem, but a solved on

10:21 Cool, that seems to work in a minimal testcase

10:21 just goes to show how bad I understand namespaces and all that

10:21 I have a namespace with an atom and that value is the same for everyone who accesses that namespace (everyone being thraeds)

10:21 so it's like a static field or something?

10:46 augustl: are there any rules of thumb for when I should use transients? Only when doing more than n updates, for example? If that's the case, what is n? :)

10:54 justin_smith: good morning everyone. I have a brainstorm to make a lib where I can describe a DAG where each node is a shell command or a closure with a method that reads as many bytes as it can get from an inputstream, and then outputs some number of bytes on an outputstream. Before I jump in, does something like this exist? basically max/msp with a mixture of unix stdin/stdout processes and clojure functions of inputstream/outputstream (without

10:54 pretty picture you get with max/msp)

10:55 or, like a shell pipeline where "tee" is implicit, and you can add/remove processes in arbitrary places in the pipeline while it is running

10:55 (and clojure functions can be inserted between programs, of course)

11:12 Xack: hm

11:12 can anyone give me an example of switching to a title-screen after so many seconds in play-clj?

11:13 sveri: Hi, is it possible to create a namespace in memory during runtime, add some records to it and then referrence these records from a different namespace just as it was normal code?

11:17 justin_smith: sveri: yes, you can do all this in a normal repl

11:19 sveri: justin_smith: yea, I just found about create-ns and intern. So, it's basically possible to have users create records which are loaded during runtime in a user specified namespace

11:19 this sounds awesome

11:19 justin_smith: sveri: not only that, you can run the ns macro at runtime

11:20 sveri: I have been watching Hickesy intro to clojure almost one year ago and now I get what he meant when he said that its possible to alter the code during runtime

11:20 justin_smith: but yes, if for some reason that wouldn't work (avoiding eval I guess?) you can use create-ns and intern

11:21 the things that won't really work in a repl (without some complexity) are gen-class and gen-interface

11:21 sveri: justin_smith: hm, eval is new to me, is it an abstraction over intern and create-ns?

11:21 justin_smith: sveri: it allows executing arbitrary code at runtime. It is the function the repl calls after reading your lines of code.

11:22 sveri: justin_smith: I see, is it as evil as eval in javascript?

11:22 justin_smith: a repl is basically (loop (-> read eval print) (recur))

11:22 godd2: sveri if you're evalling arbitrary user inputted string

11:23 justin_smith: godd2: but that seems to be the very premise of the project?

11:24 mavbozo: sveri: read-string also can execute code

11:24 sveri: http://clojuredocs.org/clojure.core/read-string

11:25 sveri: mavbozo: thank you

11:25 gfredericks: (defn eval [form] (str "#=" (pr-str form)))

11:25 oh forgot to call read-string too

11:26 sveri: So if I do eval and want to create records in a namespace I would have to add the ns declaration to the evaled form, right?

11:27 gfredericks: often with eval you wrap the call in (binding [*ns* some-ns] (eval ...))

11:27 sveri: gfredericks: does the ns have to exist? or is it created on the fly if it does not exist? and are records recreated if it did exist before?

11:28 gfredericks: ,(create-ns 'treehouse.fort)

11:28 justin_smith: sveri: ns used in a repl is exactly like ns in a file

11:28 clojurebot: #<Namespace treehouse.fort>

11:29 gfredericks: ,(binding [*ns* (the-ns 'treehouse.fort)] (eval '(inc 41)))

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

11:29 justin_smith: sveri: except for :gen-class

11:29 gfredericks: why not just use ns?

11:29 gfredericks: ,(ns treehouse.fort)

11:29 clojurebot: nil

11:29 gfredericks: ,(binding [*ns* (the-ns 'treehouse.fort)] (eval '(inc 41)))

11:29 clojurebot: 42

11:29 mavbozo: sveri: have you watch How Clojure Works http://www.youtube.com/watch?v=8NUI07y1SlQ ?

11:30 sveri: mavbozo: thank you, I did some time ago, but clojure was to new to me then, however, might be a nice fit now, thank you

11:30 mavbozo: sveri: maybe the explanation in that video can answer your questions.

11:30 sveri: (inc justin_smith)

11:30 lazybot: ⇒ 131

11:30 sveri: (inc gfredericks)

11:30 lazybot: ⇒ 104

11:30 sveri: (inc mavbozo)

11:30 lazybot: ⇒ 1

11:31 mavbozo: sveri: puredanger here pointed it to me a couple days ago. Still trying to understand though.

11:33 gfredericks: ,(defn factor [n] (let [[p] (->> (range) (drop 2) (filter #(zero? (rem n %))))] (if (= n p) [n] (cons p (factor (/ n p))))))

11:33 clojurebot: #'sandbox/factor

11:33 gfredericks: ,(factor 104)

11:33 clojurebot: (2 2 2 13)

11:37 justin_smith: mavbozo: I ended up watching that "how clojure works" vid, and it was a good overview / refresher

11:37 it also ends up setting the stage / motivation for things like arrdem 's oxcart

11:37 eric_normand: how does one read edn tagged literals in clojurescript?

11:42 gfredericks: eric_normand: looks like you can rebind cljs.reader/*default-data-reader-fn*

11:42 eric_normand: I'm confused

11:43 gfredericks: could you describe what your input is and the output you want?

11:46 that var is an atom for some reason, so you'll presumably want to bind it to (atom (fn ...)) :/

11:46 there are also the side-effecty routes via cljs.reader/[de]register-[default-]tag-parser!

11:52 I wonder what on earth is the use case for deregister-default-tag-parser

12:02 bbloom: augustl: benchmark benchmark benchmark

12:02 zeapo: Hey!

12:03 pdurbin: justin_smith: ah, you must mean https://www.youtube.com/watch?v=8NUI07y1SlQ

12:05 m1dnight_: I'm reading through the clojure style guide by batsov

12:05 justin_smith: pdurbin: yeah, I was responding to mavbozo who pasted that link above

12:05 m1dnight_: And he states that (defn foo [x] (if (pos? x) (foo x) (bar x)))

12:05 is worse than (hold on)

12:06 pdurbin: justin_smith: oh. now I see the link. thanks

12:06 m1dnight_: (defn foo [x] {:pre [(pos? x)]} (bar x))

12:06 but, in the former you can specify your own exception

12:06 is there something like that possible with preconditions

12:07 justin_smith: m1dnight_: no, they always throw AssertionErrors (which are not even Exception subclass, they are Error subclass)

12:07 m1dnight_: oh okay

12:07 thnx

12:08 luxbock: I'm stuck on this 4Clojure problem: https://www.4clojure.com/problem/121

12:09 I can get the correct form with symbol replacement easily, but 4Clojure tells me that eval is bad

12:09 so I'm wondering if my approach of building the form I want to evaluate first is misguided and I should be doing something else?

12:11 justin_smith: luxbock: eval is usually bad, not just in 4clojure

12:11 luxbock: what you need is a function or datastructure that takes a symbol, and returns the function for that symbol

12:12 luckily you have a comprehensive list of the symbols you need to use right there on the page

12:12 luxbock: hmm ok

12:14 justin_smith: luxbock: looking through people I follow on clojurescript, pretty much all of us did some kind of recursive mapping of the input, checking for nesting and recursing to calculate the nested value, or otherwise calculating a result if nothing is nested at that level

12:14 err wat - "looking through the people I follow on 4clojure"

12:14 dunno where that "clojurescript" came from

12:14 misfired brain cylandar

12:15 cylander - wtf brain

12:15 luxbock: alright that's good to know, I just wanted to avoid following a dead end path

12:35 justin_smith: how do I type-hint a protocol? can I type-hint the defprotocol, or do I need to just type-hint the implementations?

12:35 dnolen_: justin_smith: no type hinting of protocols is supported

12:36 justin_smith: dnolen_: that covers that then, thanks!

12:36 (inc dnolen_)

12:36 lazybot: ⇒ 7

12:36 justin_smith: (inc dnolen)

12:36 lazybot: ⇒ 17

12:37 kevinfish: I want to develop a pay per access server app first in clojure then eventually migrate it into a protected stand alone browser app (like perhaps on phonegap or firefox OS). Does anyone have any advise on the best way to do this? Like, which server to run (e.g. one built in clojure)? I have some experience in lisp and have been studying clojure for a while now but not written anything significant in it.

12:39 justin_smith: http server?

12:40 kevinfish: justin_smith: well, i'm thinking if I'm going to do a big chunk of the calculations on the server (to be formatted into a html template) then it might be best to have the server running clojure also.

12:40 justin_smith: http-kit is pretty awesome for a standalone if so. If you use ring, you have multiple servers to choose from and can use one in development and swap out to another in production/staging with no breakage

12:41 kevinfish: justin_smith: oops, not talking to me. sorry

12:41 justin_smith: kevinfish: yes, I was talking to you

12:41 you said server, but did not mention what kind :)

12:42 jkj: kevinfish: i'd default to nginx frontend proxy that does https itself and forwards requests to clojure-ring (jetty?) app running on somet other port in localhost

12:42 kevinfish: justin_smith: well that's pretty much the crux of my question. Should I run a clojure http server (if such exists)?

12:42 justin_smith: kevinfish: like I said, use ring, there are a bunch to chose from but they are all ring compatible

12:42 ring is a clojure abstraction for http servers

12:42 kevinfish: justin_smith: ok, I'll start googling that, thanks

12:43 justin_smith: kevinfish: "lein new ring foo" will generate a clojure project called foo using ring

12:43 and if you don't have lein, that's pretty much your mandatory first step with clojure usually

12:43 kevinfish: justin_smith: yes, got it. Did get that far :)

12:44 jkj: ....but then again... nginx-clojure thingy is probably the fastest choise, but a bit more complex to set up... using standalone app with e.g. http-kit as the server is prolly nice too but i'm for reason having some doubts on giving https to the app's care

12:44 kevinfish: justin_smith: I'm just hoping that my server code that generates the html can eventually be migrated to the browser as clojurescript with minimal changes

12:44 justin_smith: lein new ring will create a project using an embedded jetty server, but ring will let you port that to run under tomcat, or an external jetty container, or standalone httpkit or whatever

12:44 Bronsa: justin_smith: you can type hint the return value of protocol functions though

12:45 e.g. (defprotocol p (^tag f [_])) will work

12:45 justin_smith: Bronsa: inside the protocol definition? or in the definition of individual implementations?

12:45 Bronsa: AHH! that's what I was looking for, thanks so much

12:45 Bronsa: justin_smith: in the defprotocol

12:45 justin_smith: (inc Bronsa)

12:45 lazybot: ⇒ 72

12:45 justin_smith: letting dnolen_ slide without a dec, because he's awesome enough

13:19 Bronsa: so are record fields hintable too? also, is there a good document showing all the valid places for hints?

13:20 Bronsa: justin_smith: yeah record fields are hintable

13:22 justin_smith: Bronsa: do you know a blog post or a place in clojuredocs that is comprehensive and accurate about hinting positions?

13:22 Bronsa: justin_smith: both for proto fns and type/record fields primitive types are not supported btw

13:22 justin_smith: no. mostly because the clojure compiler is extermely inconsistent

13:23 justin_smith: cool, but something like ^bytes or ^"[B" would work, right?

13:23 Bronsa: yes

13:23 justin_smith: Bronsa: that's sad

13:23 Bronsa: justin_smith: my suggestin is just set *warn-on-reflection* to true and try it out

13:23 justin_smith: cool, that makes sense

13:23 we should at least have a "type hinting wiki" or something lol

13:23 or we can just come here and ask Bronsa or puredanger.

13:24 Bronsa: justin_smith: I've been complaining about it for a while, I made a clojure-dev thread a while ago but nothing came out of it

13:24 I just work around the compiler quirks now

13:25 justin_smith: arrdem: how about making this a topic on grimoir?

13:26 it's a wiki, after all

13:47 arrdem: what am I adding to Grimoire now?

13:47 wow justin is disco. first time I remember seeing that...

13:52 Bronsa: if you have and can share notes on what does and doesn't type hint I'd be happy to retype it into thalia/Grimoire

13:53 sobel: are there any well-known sites deployed on clojure-nginx that i could use for reference? (i don't want to tell my manager we'll be the first that i know of...)

13:54 even better if there's an open project i can use for tech reference but i'm prepared to manage my own code soup-to-nuts just the same

13:54 godd2: sobel clojars *might* be ?

13:54 sobel https://github.com/ato/clojars-web

13:56 sobel: hm, if it is the NC deployment bits are not in that repo

13:56 xeqi: its is not

13:56 it uses nginx to proxy to jetty

13:57 sobel: https://github.com/ato/clojars-web/blob/d69f95ab801c1482cd32721f0e9aee48d4893914/SYSADMIN.md

14:01 pdk: woah guys

14:01 i know i might not have showered yet

14:01 but you don't need to all run at once

14:01 m1dnight_: okay namespaces again.

14:01 they are killing me.

14:01 would somebody be so kind to look at what I'md oing wrong?

14:01 justin_smith: m1dnight_: specific question?

14:01 I'll take a look if you have a paste of it

14:01 m1dnight_: yeah, class nto found again

14:01 yeah ,just a sec

14:02 https://github.com/m1dnight/freakin-namespaces

14:02 this

14:02 it are two simple files and it keeps complaining about the RetryEx

14:03 I fixed it before in my other project (which utilizes both these files)

14:03 So i did the same steps for this project but i cant get it running (using lein run)

14:03 are you freakin kidding me

14:03 now it compiles

14:03 oh dear god

14:04 I changed *nothing* :|

14:04 just took a shower :p

14:04 justin_smith: m1dnight_: once again you put - in the class name

14:04 Bronsa: ds

14:04 justin_smith: m1dnight_: for generated classes - must be translated to _

14:04 m1dnight_: this was the problem you had last time

14:05 m1dnight_: yeah, I had that before

14:05 so I tried regular dashes

14:05 while figuring it out :p

14:05 because I have that indeed, in my original project

14:05 justin_smith: m1dnight_: import is for classes, - is not a valid constituent char for a class

14:05 m1dnight_: so I thought it couldve been something weird

14:05 indeed

14:06 is there some cache in leiningen i should be aware of?

14:06 All I did each time was lein clean && lein compile && lein run

14:06 justin_smith: try lein clean

14:06 OK

14:06 m1dnight_: strange, very very strange

14:06 but hey, it works :p

14:06 thnx though

14:06 justin_smith: lein compile should not be needed, lein run will do compiling if it needs to

14:06 but check out the eastwood plugin

14:07 that can help find "sketchy" stuff that isn't a compile error but is probably wrong https://github.com/jonase/eastwood

14:08 arrdem: also you don't want to chain lein via &&... lein do is your friend

14:09 unless for some reason you enjoy starting and killing JVMs

14:12 justin_smith: arrdem: so, what are your thoughts about adding an entry describing valid places for type hints?

14:12 (to grimoire that is)

14:12 arrdem: justin_smith: I'm open to it. 0.4.0 has a structure for adding full articles, and I think having a type hinted article linked to by forms that can deal with type hints makes sense

14:13 I should finish 0.4.0 someday T_T

14:13 justin_smith: cool

14:14 (defn ^HTML document [] "<head></head><body>Hello World!</body>") here's your type hinted article, all ready to go

14:14 :P

14:21 andyf: justin_smith: If you?re interested in helping writing the content of a type hinting wiki, I could help. It wouldn?t be a quick job double-checking all of the details, though, if you want it to be accurate.

14:21 justin_smith: andyf: awesome! maybe I'll throw together a draft and share it with you later

14:22 andyf: There are a *few* details in the Eastwood docs, but they don't even try to cover protocols, records, etc. https://github.com/jonase/eastwood#wrong-tag

14:42 justin_smith: andyf: how sad, with-out-str does not check "Reflection warning" messages - I was hoping I could make a set of unit tests that assert that warnings are or are not present for various definitions :(

14:44 does not capture them, I mean

14:46 andyf: justin_smith: You can with shell scripts invoking lein test and parsing the output, but a bit more work.

14:46 justin_smith: oh, wow

14:46 yeah, that's possible, but really there should be something more elegant

14:47 andyf: Wait, have you tried rebinding *err* instead of *out*? I think I do that in Eastwood and it works.

14:47 justin_smith: ,(binding [*err* *out*] (with-out-str (defn l [foo] (.count foo))))

14:47 clojurebot: ""

14:48 justin_smith: well, that also gives an empty string when reflection warnings are on

14:48 andyf: https://github.com/jonase/eastwood/blob/master/src/eastwood/util.clj#L519-L531

14:48 amalloy: justin_smith: it shouldn't

14:48 justin_smith: ,(binding [*err* *out* *warn-on-reflection* true] (with-out-str (defn l [foo] (.count foo))))

14:48 clojurebot: ""

14:48 amalloy: Compiler prints to RT.errPrintWriter, which is *err*

14:48 andyf: Then do eval inside of with-out-str2 as defined there.

14:48 justin_smith: am I doing that more?

14:48 *wrong?

14:48 amalloy: justin_smith: yes

14:48 you can't bind *warn-on-reflection* usefully

14:48 you have to either set! it, or use eval

14:49 justin_smith: amalloy: OK I was using it this way for sharing purposes, I have it turned on in a repl

14:49 amalloy: because the error is issued at compile time, whereas the binding is put in place at runtime

14:49 justin_smith: amalloy: but nothing I do seems to capture that error printout

14:49 which I do see..

14:49 andyf: justin_smith: try eval inside of my with-out-str2 or your own variant

14:51 justin_smith: ,(binding [*err* *out* *warn-on-reflection* true] (with-out-str (eval '(defn l [foo] (.count foo)))))

14:51 clojurebot: #<CompilerException java.lang.SecurityException: denied, compiling:(NO_SOURCE_PATH:0:0)>

14:51 l1x: hey guys, has anybody used clojure/tools.logging? i was wondering where should i place the log4j.properties file in the lein project tree and how could I have all the different imported Java libs logging the same way across the entire Clojure project

14:51 justin_smith: andyf: the above fails to capture it as well

14:51 amalloy: I will check out you with-out-str2

14:51 *your

14:52 andyf: Try (set! *warn-on-reflection* true) first, then that expression without warn-on-reflection binding after that?

14:52 I'll try it out locally

14:52 amalloy: s/amalloy/andyf

14:52 justin_smith: amalloy: oops, thanks

14:53 that would have made it a little harder to find

14:56 andyf: justin_smith: I can get it to work with with-out-str2, but not a small variant of your examples above. I'm heading out to lunch, so low motivation to figure out why right now :)

14:57 justin_smith: andyf: OK, thanks for the hints

14:57 maybe this is a cider issue...

15:11 $mail andyf (util/with-out-str2 (eval '(defn l [foo] (.count foo)))) did the trick, thanks

15:11 lazybot: Message saved.

15:12 justin_smith: $mail andyf turns out (with-out-str (binding [*err* *out*] (eval '(defn l [foo] (.count foo))))) does too

15:12 lazybot: Message saved.

15:13 zerkms: justin_smith: I've already had a sleep and you still here!

15:13 justin_smith: zerkms: I was only up for a few hours last night

15:13 then I slept again

15:13 either that or I am an unsleeping all-knowing immortal, you can believe that if you wish

15:14 zerkms: justin_smith: right before my daughter woke me up I've had a dream about runtime exceptions due to mutating immutable

15:14 someone was coding too much yesterday

15:14 kenrestivo: you can never code too much

15:14 justin_smith: I dreams about step debugging in cider being possible

15:14 it was glorious

15:14 Bronsa: I've found so many bugs I wasn't aware of in my code while falling asleep

15:15 justin_smith: oh yeah, and sometimes I wake up with the perfect design to solve something that I was mulling over the day before

15:15 kenrestivo: hammock-driven debugging

15:16 zerkms: "My MacBook Pro has gone to sleepZZZzzz…" <--- why people still do that :-S

15:16 Bronsa: I like to think that t.a wouldn't be as good as it is now if it wasn't for andyf and my hypnagogic thoughts

15:16 justin_smith: I think it is automatic - or do you mean leave the sleep function on?

15:16 rkneufeld_: zerkms: a lot of clients do it by default :(

15:17 zerkms: I mean - pointing out mbp

15:17 * zerkms wrote ^ ^ from their thinkpad

15:17 justin_smith: it's kind of like "my mercedes is parked a few blocks away" - mention the brand at every juncture if it's a status symbol

15:17 rkneufeld_: zerkms: it seems to be the default for Textual.app

15:18 I have a bouncer, but I just changed mine from that exact message, having never set it to that.

15:19 justin_smith: Bronsa: so I figured out how to capture the reflection warnings as strings, so I should be able to make the documentation as a github repo where you are meant to read the tests, and you can run them to verify that every claim in the codebase is accurate

15:19 since each claim would be made in the form of defining something that may or not induce a reflection warning

15:19 as long as the warnings are consistent and accurate, we're golden

15:21 amalloy: so justin_smith, what is different about with-out-str2 that makes it work where the binding/eval approach didn't?

15:21 justin_smith: amalloy: see my second mail to andyf - with-out-str / binding / eval worked too, I was just nesting things wrong

15:21 amalloy: oh good

15:22 justin_smith: "(with-out-str (binding [*err* *out*] (eval '(defn l [foo] (.count foo))))) does too"

15:23 my mistake was putting the binding outside the with-out-str

15:23 instead of visa/versa

15:23 amalloy: hah, indeed

15:24 justin_smith: amalloy: btw if you restart lazybot it should have commands in /msg working again

15:24 SagiCZ11: hi, i guess that relying on indexes is not a good programming practice, but can i assume that in map entry, the value is always 'second'? or is there a better way to acess it?

15:24 amalloy: &(doc val)

15:24 lazybot: ⇒ "([e]); Returns the value in the map entry."

15:25 justin_smith: SagiCZ11: it is always second, but as amalloy indicates, val is more clear

15:25 amalloy: SagiCZ11: use val, or destructure it

15:25 (let [[k v] e] ...)

15:25 augustl: I have an object that is in a vector with ~millions of items in it. Is it fast to get the index of that object in the vector?

15:25 amalloy: no

15:26 SagiCZ11: amalloy: thanks a lot.. i knew about vals, didnt know about val, btw is the destructuing form calling second or val on this example?

15:26 justin_smith: augustl: if you knew the index, getting the element at that index would be relatively fast

15:26 augustl: amalloy: k, thanks :)

15:26 justin_smith: or if it were a sorted-set

15:26 amalloy: SagiCZ11: well, it's calling (nth e 2)

15:26 er, (nth e 1)

15:26 augustl: the idea is to store the history of an atom in some sort of data structure. It probably makes sense to store "version" in the item itself, then

15:26 SagiCZ11: amalloy: i see, but i guess 'val' states my intentions better

15:27 augustl: this is all nice and single threaded etc ;)

15:27 SagiCZ11: augustl: wouldnt you use meta data for that?

15:28 augustl: well, the version is part of the domain, so it makes more sense to have it in the item itself imo

15:28 it's just a map anyways, so adding version to it is not a problem

15:28 justin_smith: augustl: what about putting it in a proper persistent storage (ie. a db of some sort)

15:28 if you care about all the versions it has had in a session, maybe you would also care between sessions?

15:29 augustl: that could also work. It's an experiment at this stage, I want to see how much history I can store with persistent data structures

15:29 but old data isn't vital to the system, it's only used for "support" tasks so we can know what the data looked like at a given point in time to reproduce bugs etc

15:29 SagiCZ11: augustl: why do you need the history? just wondering, sounds memory intensive

15:31 i see

15:31 amalloy: justin_smith: yep, looks good

15:32 augustl: don't say Datomic!

15:32 justin_smith: augustl: postgres or mysql would do the job just fine

15:33 augustl: justin_smith: implementing persistent data structures on top of SQL? Doesn't sound trivial :)

15:33 justin_smith: augustl: why persistent? just don't use alter

15:33 err update

15:33 just create new records

15:34 amalloy: SagiCZ11: right, val is good if you only care about the val. if you need both key and val, destructuring is usually clearest

15:34 augustl: the state consists of a couple of hundreds of entity per day, that gets modified as time passes

15:34 SagiCZ11: amalloy: alrighty

15:34 augustl: justin_smith: so that's the tricky part - modifying the entities

15:34 clojurebot: excusez-moi

15:35 justin_smith: augustl: there are well established techniques for keeping extensive records and also keeping the db manageable. One basic idea is to only create new records, never modify old ones, and as the db grows, move the oldest ones into a different database (perhaps on another server) so all the data is still available, but the oldest data is not slowing down your most heavily used set

15:36 augustl: yeah sure, but that still means I'm the one that have to model time, if I need that I prefer to drop in something that does the job for me :)

15:37 justin_smith: augustl: multiple entries with the same id key, the one with the newest time field is the actual current value

15:40 sveri1: justin_smith: augustl I have been doing that in a larger php application with mysql some time ago, you can get started easily, but it somehow became PITA fast, escpecially as we switched to java / hibernate and were not really able to modle our datastructure to hibernate, part of the reason was the history. So I am not saying it cannot be done, but you really have to take care to do it right

15:41 justin_smith: sveri1: yeah, I am sure hibernate wasn't very cooperative

15:41 augustl: hibernate is great, you can just think of your objects as in-memory objects and stuff will just work, no problems whatsoever. Right?

15:42 zerkms: "never modify old ones, and as the db grows, move the oldest ones into a different database" --- we employ the same scheme ^2

15:42 it's called bitemporal (if someone didn't hear)

15:42 so you not only have audit for the records but audit for audit as well

15:42 justin_smith: zerkms: thanks for the lingo :) - I had heard of the technique but not the name

15:44 zerkms: the wikipedia page for temporal database says postgres supports it directly - is that the db you used?

15:44 zerkms: http://en.wikipedia.org/wiki/Temporal_database#Using_Transaction_time

15:44 we use postgresql but it's implemented on application level

15:44 justin_smith: cool

15:44 zerkms: ... in php

15:44 :-D

15:44 * zerkms is a php developer

15:45 sveri1: augustl: uhm, no, you also have to know about all the quirks you can run into with hibernate, you better read a lot before you use it

15:45 augustl: sveri1: was kidding ;) Painfully aware of the quirks

15:46 sveri1: augustl: hehe, I hoped that, but wanted to make sure in case someone thinks, hey, cool, lets just use it :D

15:47 justin_smith: sveri1: augustl: ever see the wikipedia page for object-relational-impedence-mismatch? parts of it read like a paragraph by paragraph argument between a db guy and a java dev last I looked

15:47 sveri1: actually, at my current job we decided to do some auditing into database and did it via jdbc, funny moment when the consultants asked why we did not use hibernate and I had to keep calm not starting ranting about it

15:47 justin_smith: http://en.wikipedia.org/wiki/Object-relational_impedance_mismatch

15:47 augustl: justin_smith: haha

15:50 mavbozo: besides datomic, are there any temporal database that has in-memory storage?

15:50 augustl: are there any temporal databases besides datomic?

15:51 justin_smith: augustl: the wikipedia page mentions a few, but does not mention datomic at all http://en.wikipedia.org/wiki/Temporal_database

15:52 augustl: most of them seems to be audit hacks over row based rdbms-es

15:52 zerkms: guys, how would you unit test a function that writes into a channel synchonously? For sake of simplicity let's say it just accepts a channel and writes to it

15:53 mavbozo: zerkms: what's the function output?

15:54 justin_smith: zerkms: create the channel and a very small block of code that sleeps than reads. Verify that the write was synchronous based on timing, and verify correctness as apropriate.

15:54 zerkms: it does not matter in this case. let's say `nil`

15:54 justin_smith: what if function is broken and *does not* write to the channel?

15:54 mavbozo: well, why test a function that already been tested by core.async devs?

15:54 zerkms: does it mean we would use alts!! in the unit test to save ourselves?

15:54 justin_smith: zerkms: then kill your unit test, and consider it failed - hanging is clearly failure

15:55 zerkms: mavbozo: I'm testing my function, which sometimes may be broken

15:55 justin_smith: hm, so how the overall call would look like?

15:56 and what unit testing framework it is trending?midje?

15:57 sveri1: zerkms: clojure.test

15:57 zerkms: ok

15:58 I've seen people use them together - clojure.test as main assertion library and midje as aux for re-running and some additional check functions

15:59 justin_smith: (let [then (.getTime (Date.)) ch (chan) reader (go (Thread/sleep 300) ...)] (do-block-write ch) (is (> 300 (- (.getTime (Date.)) then)))) ; this is a general idea at least

15:59 zerkms: justin_smith: yep, exactly like I thought. Thanks

16:00 justin_smith: there may need to be a unit conversion in case sleep and .getTime aren't the same unit...

16:00 I always forget

16:01 &(- (.getTime (java.util.Date.)) (do (Thread/sleep 300) (.getTime (java.util.Date.))))

16:01 lazybot: ⇒ -319

16:01 justin_smith: looks about right!

16:02 of course you can be all fancy and wrap the time stamping in a more readable function, I like naming it "stamp" as in time-stamp

16:02 zerkms: yep

16:02 I actually asked because I expected unit testing frameworks to already include shortcuts

16:03 since it looks like a frequent pattern

16:04 justin_smith: zerkms: hmm, that's a good question

16:06 zerkms: somthing like (delayed-call [fn timeout]) perhaps

16:06 err: not delayed, cannot think of a good name

16:06 timeouted-call :-D

16:07 justin_smith: a grep of the midje sources didn't find anything promising at a first scan

16:10 nor does expectations

16:24 dbasch: &(System/currentTimeMillis) justin_smith

16:24 lazybot: ⇒ 1416086635094

16:25 justin_smith: dbasch: I keep forgetting that one

16:26 dbasch: there’s also ##(System/nanoTime)

16:26 lazybot: ⇒ 12615169313167376

16:26 justin_smith: &(> (count "(System/currentTimeMillis)") (count "(.getTime (Date.))"))

16:26 lazybot: ⇒ true

16:26 justin_smith: :P

16:26 dbasch: but do a benchmark :P

16:26 justin_smith: OP

16:26 fair point

16:27 yeah, that creates an object I don't really need, of course that will be slower

16:28 zerkms: ##(System/nanoTime) <--- what ## means here?

16:28 lazybot: ⇒ 12615336358064166

16:29 dbasch: surprisingly my benchmark shows they’re almost the same

16:29 SagiCZ11: zerkms: it just tells lazybot to evaluate what follows

16:32 i am having memory issues again.. it's weird, maybe clojure makes me forget some basic stuff.. but i almost never got a leak in java

16:33 is there anything suspicious memory-wise about this line?

16:33 (with-open [r (io/reader file-path)] (apply str (interpose \newline (next (line-seq r)))))

16:33 rs0: looks like that will buffer the entire file in memory

16:33 zerkms: you read whole file into memory

16:34 SagiCZ11: i need to since i want to write it to a different file

16:34 justin_smith: well, except for the newline

16:34 rs0: SagiCZ11: no, you don't

16:34 andyf: SagiCZ11: str creates a Java StringBuffer and appends to it. Memory-wise, I would expect that to first allocate a separate string for each line of the file, and then append them all, which could require several reallocations.

16:34 rs0: SagiCZ11: you stream it from one file into another

16:34 andyf: Maybe you just want slurp ?

16:34 justin_smith: SagiCZ11: what about string/join instead of apply string on interpose? that should perform much better

16:34 SagiCZ11: andyf: i would use slupr but i need to omit the first line

16:34 rs0: SagiCZ11: why not just call a filesystem copy operation?

16:34 zerkms: justin_smith: isn't it the same?

16:34 rs0: ah, ok

16:34 justin_smith: no

16:35 zerkms: I've read that clojure optimizes them both to StringBuilder

16:35 andyf: SagiCZ11: Use .indexOf to find the first newline, and then print out a substring of the string in memory

16:35 justin_smith: zerkms: interpose creates the collection, and then passes that to string

16:35 *str

16:35 zerkms: but collection must be lazy

16:35 justin_smith: zerkms: whereas string/join directly works with a stringbuilder, skipping a bunch of intermediate stuff you don't need

16:35 andyf: subs will allocate a new string, so you might want to avoid that, and see if there is a way to write out a substring of an existing string without explicitly allocating one, which would require looking up Java docs.

16:36 justin_smith: zerkms: sure, but str is not, so apply str forces the whole thing

16:36 zerkms: yes, but str is built on top of StringBuilder

16:36 justin_smith: zerkms: sure - but interleave still has to run

16:36 zerkms: which must be as efficient as string/join

16:36 justin_smith: no

16:36 zerkms: ok

16:36 rs0: clearly the solution here is to use (drop 1) as part of a transducer stack

16:36 justin_smith: interleave still runs

16:36 zerkms: the lazy seq still has overhead

16:36 dbasch: SagiCZ11: all you want to do is write everything but the first line?

16:37 SagiCZ11: also, i cant leave it lazy inside the with-open call, i have to evaluate it

16:37 justin_smith: you are creating cells and immediately throwing them away

16:37 SagiCZ11: dbasch: i guess? but i am joining multiple files (without their first line) together

16:37 dbasch: SagiCZ11: still, you don’t need to keep anything in memory except for the line you’re reading/writing

16:37 rs0: SagiCZ11: just checking--is there a reason you're doing this with Clojure and not a bash script?

16:38 SagiCZ11: rs0: i know little about clojure and less about bash

16:38 andyf: SagiCZ11: If you want to make it as memory-friendly as possible, I'd recommend slurp, followed by Java String .indexOf, followed by write a subset of the string without allocating a new one, e.g. the write method that takes an offset https://docs.oracle.com/javase/7/docs/api/java/io/Writer.html#write(char[],%20int,%20int)

16:38 dbasch: SagiCZ11: by join you mean concatenate all fhe files minus the first line?

16:39 SagiCZ11: andyf: i see.. i still dont understand how could that not fit into 1 GB of heap space

16:39 rs0: andyf: why not just use a BufferedInputStream and call readLine? you don't need to index into the string

16:39 andyf: er, i'm thinking of BufferedStreamReader. or something. not sure what the clojure equivalents are, if any

16:39 andyf: SagiCZ11: Actually, if you really want it to be memory friendly, then just alternate reading and writing single characters, or a small string buffer of a fixed size. Don't slurp at all.

16:39 justin_smith: rs0: all java classes are available in clojure

16:40 rs0: justin_smith: I realize that, but there are a lot of more idiomatic wrappers around a lot of the java IO classes. slurp and spit are great examples

16:40 justin_smith: nobody wants to write new BufferedReader(new InputStreamReader(System.in)) in java *or* clojure

16:40 SagiCZ11: andyf: yeah i wanted a simple solution, the files in question are 120 MB total, why wouldnt they fit in the heapspace i dont understand

16:41 justin_smith: rs0: sadly, there is no good wrapper for BufferedReader (I know this because it is needed for read)

16:41 andyf: SagiCZ11: If you know lines are typically short, you can modify your original example using line-seq to write the line strings inside the with-open, and never append strings together.

16:42 justin_smith: rs0: and if there were, it would just be a function in clojure.java.io that would be implemented as #(BufferedReader. %)

16:42 andyf: SagiCZ11: If they are ASCII or mostly so, then note that reading them as strings converts every byte of file into 2 bytes of UTF-16 in Java strings in mem

16:42 rs0: "short" meaning, say, a few kilobytes

16:42 SagiCZ11: andyf: i need the files zipped.. i have a function which takes a file name and a huge strings, and creates zip file containg one text file with all the files concatenated together.. i dont think i could zip it line by line

16:42 rs0: SagiCZ11: if you're writing this as a standalone program for a one-off task, Clojure is almost certainly the wrong choice. you want a scripting language

16:43 andyf: SagiCZ11: I haven't done it before, but there are Java classes like BufferedReader / writer that can be 'layered' on top of other readers/writers that zip it while streaming through.

16:43 dbasch: SagiCZ11: that’s trivial in bash

16:43 SagiCZ11: :(

16:44 justin_smith: zerkms: about a 4x difference in performance https://www.refheap.com/93437

16:44 rs0: in bash you could do something like

16:45 (for i in file1 file2; sed -e 1d $i) | gzip > output.gz

16:45 SagiCZ11: i don't even have bash

16:45 dbasch: SagiCZ11: are you on a windows box?

16:45 andyf: SagiCZ11: is it convenient to use a shell script in your context? It might save time if so. If it helps to have it in Clojure, it can be done without using much memory.

16:47 I haven't used the Java Zip writer/stream classes before, but here is a Java example of some of the classes available: http://stackoverflow.com/questions/4308276/how-to-zip-a-file-while-writing-to-it

16:47 SagiCZ11: dbasch: yes, sorry

16:47 andyf: i dont know.. i also have functions that recognize the format of the file, and convert it to a correct one and such things, i dont think i could do this in bash when i dont have no experience with it

16:48 andyf: I don't know of anything already written in Clojure for this. Nothing in clojure.core, I'm almost certain, but there may be a Clojure lib. The thing is, if you know the few Java classes needed, it looks like not many lines of Java interop in Clojure

16:48 SagiCZ11: it says OutOfMemory exception but i dont see it hitting the heap space limit in jvisualvm..

16:49 rs0: SagiCZ11: it's also possible that the JVM is trying to allocate an array with too many elements (more than Integer.MAX_VALUE)

16:49 andyf: a good way to be certain this won't cause memory issues is to write it using methods/classes that process/zip/etc. the file contents as the data flows through, without ever allocating strings containing complete file contents.

16:49 rs0: SagiCZ11: which you can't fix by increasing your heap size

16:49 SagiCZ11: it just does this little hop and crashes http://i.imgur.com/mPSVcKV.png

16:50 justin_smith: SagiCZ11: and the crash is an oom?

16:50 SagiCZ11: rs0: it says it on Arrays.copyOf call, so that might be possible

16:50 justin_smith: yes, OutOfMemoryError Java heap space java.util.Arrays.copyOf

16:51 whats the max array size in java?

16:51 i have about 1 200 000 elements in it i guess

16:52 justin_smith: SagiCZ11: IIRC it is ##(Integer/MAX_VALUE)

16:52 lazybot: ⇒ 2147483647

16:52 SagiCZ11: i see

16:52 so weird

16:52 rs0: does anyone know how to do this in powershell?

16:54 SagiCZ11: wait.. if the string is backed by a single array..

16:54 justin_smith: SagiCZ11: this best answer would be maybe 7 lines of clojure interop tops http://stackoverflow.com/questions/1091788/how-to-create-a-zip-file-in-java

16:55 SagiCZ11: and it can be adapted to write a fixed buffer size at a time in a loop

16:56 or a line at a time, or whatever

16:56 SagiCZ11: thanks..

16:56 justin_smith: SagiCZ11: note the putNextEntry call - that starts a new file, so you could create arbitrary files as you stream

16:56 (new file within the same zip file, that is)

16:57 SagiCZ11: i only ever want one file in one zip file

16:57 justin_smith: even easier :)

16:58 SagiCZ11: i dont like manipulating bytes directly, seems to low level

16:58 rs0: SagiCZ11: i'm with you on that

17:00 amalloy: SagiCZ11: are you trying to work with zip files? have you looked at https://github.com/Raynes/fs/blob/master/src/me/raynes/fs/compression.clj ?

17:00 justin_smith: SagiCZ11: something like (let [f (io/file "d:\\test.zip") out (java.util.zip/ZipOutputStream. (io/output-stream f)) e (Zipentry. "mytext.txt") lines (next (line-seq source))] (.putNextEntry out e) (doseq [line lines] (.write out (.getBytes line))) (.closeEntry out) (.close out))

17:01 rs0: SagiCZ11: i think from a long-term perspective, the best thing for you to do is either to learn powershell or bash (install cygwin since you're on windows)

17:01 sveri1: SagiCZ11: go the cygwin route, its more portable than powershell

17:02 SagiCZ11: amalloy: i didnt find anything when i was looking for it, thanks

17:02 justin_smith: thank you

17:02 justin_smith: SagiCZ11: that code is not guaranteed to work, but should be a decent start if cross referenced with that SO link I posted

17:03 SagiCZ11: justin_smith: thanks this helped a lot, i didnt know how to do this

17:04 justin_smith: while this is much easier to do in bash, I think the exercise in translating java idioms to clojure interop is useful

17:04 SagiCZ11: rs0: i definitely do need to learn bash.. you are right, but as justin_smith just said, i need to learn clojure as well, so at least its an exercise

17:05 rs0: SagiCZ11: if you already know java, you'll get more benefit out of learning bash than out of learning clojure

17:05 SagiCZ11: and i'm an enormous fan of clojure

17:05 SagiCZ11: rs0: and even a bigger fan of bash i see

17:05 rs0: SagiCZ11: no, it's just a matter of marginal utility. better to know one scripting language and one JVM language than no scripting languages and two JVM languages

17:06 SagiCZ11: justin_smith: so in your example, if i have 'lines' as an input and keep them always lazy before entering the packing function, the whole string would be never realized in memory, correct?

17:06 justin_smith: correct

17:07 SagiCZ11: justin_smith: thank you

17:08 justin_smith: SagiCZ11: I've actually proved this with the profiler before (I may have the code around somewhere) - the clojure compiler can tell when lines can't leave scope, and when it's head is not accessed, and when both of these hold true it does not hold onto used items

17:09 SagiCZ11: rs0: i have written some bash scripts.. for initializing our company database after boot up and i didnt enjoy it very much.. it all seemed complicated and non-standard. also, since i dont have a linux machine, where you use bash all the time, it would take me a lot of time to learn

17:09 rs0: SagiCZ11: you can get the basics done with cygwin. bash is weird and mediocre but there's nothing even remotely as useful for day-to-day automation

17:10 SagiCZ11: justin_smith: i see, thats good stuff

17:10 rs0: SagiCZ11: i gave you a one-liner that basically uses sed, gzip, and IO redirection to do something that you can't even do in clojure without a nontrivial amount of code

17:12 although i think i technically used the zsh for loop syntax

17:12 SagiCZ11: rs0: but i just gave a minimal example, what i do is way more complicated, also because i dont know all about the source files, i need to explore them and REPL and file-sqeq is fantastic in this, but i guess bash has no problem filtering or printing first lines or anything for that matter

17:13 rs0: fair enough. but you can do some very very sophisticated things with unix because the tools compose so well

17:14 justin_smith: rs0: SagiCZ11: right now I am trying to translate a bash script that randomly fails into a clojure program that interconnects program inputs and outputs and makes sure each of those programs stay running. So on the one side I wish using clojure for shell processes were easier, on the other side I wish reliability in shell programs was easier.

17:14 rs0: very true, regarding tool composition

17:17 SagiCZ11: justin_smith: one more little thing to the previous topic, with this approach i avoid realizing the whole files in memory, but then i cant use (with-open) on the source file right? i will need to rearange my code to close them manually

17:17 justin_smith: SagiCZ11: actually that could be adapted to with-open, just take out the close call and move the opening call out to the with-open

17:18 SagiCZ11: I just tried to keep it literally line by line the same as the java logic

17:18 SagiCZ11: i mean on my source files not on the destination files

17:19 rs0: justin_smith: shouldn't that be an Erlang program? =)

17:19 justin_smith: well, you could do (with-open [dest "dest-file"])

17:20 rs0: lemme just go tell the client they can't demo the product on monday because I can't complete my job until I learn erlang first. I am sure that will go over swell :)

17:20 rs0: in all seriousness, I bet this would be very easy to do in erlang, and I may just spend some time learning it if I keep doing work like this

17:24 rs0: justin_smith: I'm not sure what you mean by "randomly fails"

17:24 justin_smith: are these processes communicating over ordinary pipes?

17:24 olivierrr: https://github.com/functional-koans/clojure-koans/blob/master/src/koans/13_recursion.clj#L4-7

17:25 justin_smith: rs0: yes

17:25 rs0: justin_smith: i wonder if you could use a FIFO as the unix equivalent of a BlockingQueue

17:25 justin_smith: rs0: 3 input sources, each of which multiplexes to 12 data format translators, which each feed an analyzer, which then feeds into a clojure program handling all 36 inputs

17:26 and yes, this is using fifos at the process / clojure barrier

17:26 rs0: neat!

17:26 justin_smith: rs0: the trick is keeping track of 36*2 + 3 programs

17:26 because that's a lot to keep track of...

17:27 rs0: what do you have to keep track of? just running/dead, so you can nanny processes that fail?

17:27 SagiCZ11: and how would i add a newline after each line to the zip file?

17:27 justin_smith: rs0: mostly just running/dead. my shell skills don't scale nicely to that kind of process count

17:28 SagiCZ11: (.getBytes

17:28 "\n")

17:28 rs0: justin_smith: have you found any off-the-shelf solutions that do this kind of multi-process nannying at scale?

17:28 justin_smith: sorry, hit return by mistake

17:28 SagiCZ11: so its not \newline anymore?

17:28 justin_smith: rs0: haven't, no

17:28 SagiCZ11: \newline is a character, that method expects a byte array

17:28 the write method, that is

17:29 rs0: there is probably some awesome tool that would make this simple and I have been wasting my time :)

17:29 rs0: justin_smith: have you looked at Upstart?

17:29 SagiCZ11: so it would be (.getBytes (s/join line "\n")) ?

17:29 rs0: justin_smith: or even conventional init.d scripts?

17:30 justin_smith: rs0: so I set up 75 init scripts?

17:30 rs0: an init script ensures that one program is running, as I understand it

17:31 rs0: justin_smith: i'm wondering if Upstart is more sophisticated than its system v ancestor. the "asynchronously start a process and then nanny it in case it dies" aspect of Upstart seems like it might be a good fit for your problem. but i don't know what else it's complected with

17:33 justin_smith: rs0: I can't reinstall the os, it is OpenSuSe 11.1

17:33 I don't think upstart runs on that

17:34 SagiCZ11: ,(.getBytes "hello")

17:34 clojurebot: #<byte[] [B@bf47df>

17:34 SagiCZ11: ,(.getBytes (conj "hello" "\n"))

17:34 clojurebot: #<ClassCastException java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IPersistentCollection>

17:35 rs0: ,(.getBytes (str "hello" "\n"))

17:35 clojurebot: #<byte[] [B@1905335>

17:35 justin_smith: SagiCZ11: why not just output the "\n" as a separate write step?

17:35 SagiCZ11: justin_smith: why not indeed.. havent thought of that.. that way i avoid another array copy

17:37 llasram: &(let [{:keys [:foo]} {:foo "bar"}] foo)

17:37 lazybot: ⇒ "bar"

17:37 llasram: Is that intentional

17:37 ?

17:37 Bronsa: yes

17:37 since 1.6

17:37 llasram: Ok, good

17:37 Bronsa: it's to support destructuring of :: style keywords

17:37 llasram: That's what I thought + vaguely rememered

17:38 Bronsa: ,(let [{:keys [::foo]} {::foo "bar"}] foo)

17:38 clojurebot: "bar"

17:38 llasram: Explicitly namespaced symbols work too, but namespace aliases aren't resolved, which makes them rather more clunky :-(

17:38 Bronsa: yeah

17:39 akhudek: hmm, so honeysql doesn’t support unions or intesections it seems

17:39 SagiCZ11: after all the changes i no longer have any memory issues... thank you all for the ideas, tips and help

17:42 olivierrr: https://github.com/functional-koans/clojure-koans/blob/master/src/koans/13_recursion.clj#L4-7

17:42 stuck on that koan, anyone got some hints?

17:42 Bronsa: olivierrr: is 0 even?

17:43 olivierrr: i think so

17:43 Bronsa: olivierrr: and if n-1 is even? is n even?

17:43 llasram: olivierrr: May also help to notice that they pretty clearly only expect a solution which works with non-negitive integers

17:43 olivierrr: Bronsa: no

17:44 Bronsa: olivierrr: you just solved that koan then, just write those answers in the clojure code

17:44 llasram: Oh geez, Github's syntax-highlighting for Clojure is still kind of crazy

17:47 akhudek: does anyone know of something like honeysql that does support union?

17:47 olivierrr: aah, got it Bronsa, thanks

17:47 Bronsa: olivierrr: np

18:06 technomancy: llasram: I heard they stopped using pygments in favour of textmate highlighters

18:07 http://p.hagelb.org/sisko.gif

18:07 llasram: An interesting descision

18:07 technomancy: textmate. highlighters.

18:07 llasram: I'm sure they had legitimate reasons

18:08 derp: does anyone here use ergoemacs for clojure development?

18:10 technomancy: derp: in general "starter kit" type things cause lots of problems and aren't widely recommended here

18:10 (speaking as the creator of the first starter kit)

18:36 andyf: Bronsa: Holy cow. I just ran latest Eastwood against clojure.core and it didn't throw an exception. I haven't tried in almost a year.

18:38 Bronsa: andyf: nice!

18:40 andyf: I was updating some slides about Eastwood for hiredman to use at the Conj if he wants them, was writing some exceptions that we do not test against, and decided to double-check whether it really is still a problem. I had assumed it would always cause problems for one reason or another, what with all that early bootstrap code, and defining fundamental macros.

18:41 Bronsa: andyf: well t.e.jvm has been able to compile clojure.core for a while now so it makes sense that eastwood does too

18:42 andyf: ok, didn't realize that.

18:42 No bugs found :)

18:42 lots of warning, but not bugs

18:43 Bronsa: once I get to fix tanal-100 I'll release t.a/t.a.j 0.7.0

18:48 andyf: FYI it is highly likely that in the next release :raw-forms will store info about the fully resolved var name, I still haven't made up my mind on what's the best approach

18:49 andyf: ok. You may have noticed that I have :eastwood/partly-resolved-forms added in Eastwood, since it is useful in some places to avoid mistaking which Var is first.

18:50 It only resolves the first var in each :raw-forms element

18:51 Bronsa: andyf: I have indeed. And I'd be happy to keep it as is if it wasn't that it's possible - even though unlikely - that the ns env mutates during macroexpansion, possibly making a later resolve-var inconsistent with the one that originated the macroexpansion

18:51 allenj12: has anyone here used enclog before?

18:51 https://github.com/jimpil/enclog

18:52 andyf: Bronsa: the stuff of nightmares

18:54 Bronsa: andyf: and then there's always the issue that since the macroexpander is open, I have to be careful with the assumptions I make in t.a about what macroexpand will return

18:55 andyf: ideally the best approach would be to let the macroexpander guide :raw-forms, but I'm still trying to decide if complicating the impl is worth it

18:56 t.a.jvm's macroexpander is already quite complex with all the desugaring it needs to to

18:57 andyf: I'm collecting a few statistics for the updated eastwood slides. Didn't realize I've filed 73 tickets on tools.analyzer. Looks like my 'batting average' (baseball term) is 58/73=0.795 for non-declined/duplicates :)

18:57 Bronsa: heh

19:52 derp: does someone have an emacs config streamlined for clojure dev

20:11 :technomancy haha I actually used your starter kit!

20:13 :technomany thanks for telling me to be weary of starterkits

20:54 arrdem: I should open source my emacs config at some point...

20:54 for *nix hosts it's modular enough to be a "starter kit" within reason

20:54 technomancy: down that road lies madness

20:55 but it's good to have something from which others can steal ideas

20:55 nice to be able to just drop a URL in chat too

20:56 arrdem: eh it's madness only if open srcing makes you clean/maintain it beyond what you find usable

20:57 technomancy: just don't let anyone use it as a starter kit

20:57 the moment you get a pull request, burn it to the ground

20:57 * arrdem chuckles

21:12 oskarkv: Hm does anyone know of a way/tool to get a dependency graph of dependencies between functions?

21:13 gfredericks: I have a half-assed library that does that

21:13 although I guess if you didn't mean visualization in particular it might not be as helpful

21:14 maybe you could rip some code out of it

21:14 https://github.com/gfredericks/clj-usage-graph

21:15 oskarkv: ^

21:15 oskarkv: gfredericks Thanks i'll take a look. I wanted to visualize my own code. :P

21:20 csd_: Is it bad style to use an atom within a let statement, and mapping an anonymous function that increases the atom as it operates?

21:23 dnolen_: csd_: generally bad style unless there's a really good reason

21:24 gfredericks: csd_: it smells like reduce

21:24 csd_: just rewriting some CL that does the same thing, curious what would be idiomatic clojure

21:24 i'll see if i can use reduce

21:37 andyf: Sometimes (like now), I wish I had something like with-out-str, except it limited the size of the string produced to a max specified length in chars, to keep the output (intended for debugging) short. Ideally it could even allow the body that prints the output to stop immediately if it reached that limit, but I'm guessing that isn't easy or even possible to implement.

21:38 gfredericks: a special print-writer thing?

21:38 it could throw an exception when you get to the limit

21:39 (throw (ShutUpError.))

21:41 andyf: gfredericks: I guess I could write a new subclass of StringWriter ...

21:41 gfredericks: everything is solvable via another subclass of something

21:42 justin_smith: gfredericks: could one write a useful program where the only thing you do is make subclasses of things/

21:42 gfredericks: I believe so

21:42 perhaps in the context of a subclassing framework?

21:42 justin_smith: this would be an interesting esolang maybe

21:42 gfredericks: do we get to use interfaces too?

21:42 justin_smith: hmm

21:43 andyf: and yeah, throw an exception if it hits the limit, thrown from the append method or something like that, and document the behavior so people hopefully won't use it for capturing output of code that fails to clean up if the exception is thrown

21:43 gfredericks: andyf: you gonna throw this in a real-life for-other-people library?

21:43 justin_smith: andyf: with-lazy-charsequence, using a lazyseq of char?

21:44 andyf: Not yet, anyway.

21:44 My current desire is that I like to use clojure.inspector to examine tools.analyzer ASTs, but sometimes the strings produced are so long that it is too slow or memory-intensive.

21:44 In those cases, I won't be looking at the entire contents of the strings anyway, only the first 200 chars or so.

21:44 gfredericks: those ASTs are not very tree-like

21:45 last time I looked at them

21:45 andyf: not sure I see why they aren't tree-like

21:45 gfredericks: andyf: I think there's supposed to be a cider something-something for this use case

21:45 andyf: some kind of cider data-inspector?

21:46 gfredericks: andyf: I meant not tree-like in the sense that they have a lot of objects that appear multiple times

21:46 andyf: yes

21:46 andyf: it is an implementation detail whether those things are identical or not :)

21:46 but it is a lot faster that they are identical

21:46 gfredericks: it might not fit in memory otherwise

21:47 and it might not reasonably print regardless

21:47 andyf: sure, DAG in implementation, but tree as represented in the inspector. I remove a few keys throughout before inspecting them, most times, and it is useful to use an ordered-map from the useful lib to guarantee keys are in a particular order, for debugging.

21:48 gfredericks: such like ##(nth (iterate (partial repeat 10) 42) 10)

21:48 andyf: I'll remember the cider thing for possible future reference, but that is a yak I don't want to shave today

21:48 lazybot: java.lang.OutOfMemoryError: Java heap space

21:48 andyf: I'm strictly emacs+clojure-mode now

21:48 gfredericks: minimalist

21:48 justin_smith: andyf: with inferior-lisp?

21:49 andyf: I pick my battles, and cider sounds like a hassle I don't want yet

21:49 justin_smith: Eastwood I test so often from the command line, I am (gasp!) often debugging with printf and re-run

21:50 justin_smith: andyf: ah, so not even inferior-lisp then.

21:52 andyf: Perhaps I should make a slide including this to demonstrate my development workflow, where I'm one of the cavemen in front: http://s238.photobucket.com/user/JeffreyBSG/media/cavemen_zps869695fb.jpg.html

21:52 But I look more like the guy in the back

21:52 can't say I actually feel the pain of what I'm doing, if there is any. Gets the job done.

21:55 justin_smith: andyf: the main thing I would miss is auto-complete

21:56 andyf: emacs dynamic-abbrev works

21:57 although maybe the auto-complete you mention does something dynamic-abbrev does not

21:57 justin_smith: andyf: does dynamic-abbrev complete names that you require from libraries but don't have open in buffers?

21:58 andyf: no, so that is a difference

21:58 I don't close many buffers, though, and have same emacs running for weeks at a time

21:58 justin_smith: andyf: oh, that is the name for what M-/ does!

21:58 I use that often

21:59 josiah14: granted I already have a working underrstanding of Java, Ruby, and Haskell, what's the relative difficulty in learning Clojure? Is it something I could power through a tutorial on in a week or two and then figure out something like the Caribou framework in a month or less (given I have used Rails, but not anything for Haskell like Snap)

21:59 justin_smith: josiah14: if you know all three, it will just be the syntax. And the syntax is very simple.

22:00 josiah14: hmm. cool

22:00 justin_smith: I mean clojure has its quirks, anything does

22:00 but I don't think it has much that one of those doesn't, other than lispy syntax

22:01 andyf: josiah14: A book like Emerick et al's Clojure Programming would be handy

22:01 josiah14: i was reading on some websites that those new to Clojure might have trouble picking up something like Caribou, but I didn't know if that was because the assumption is that newcomers would be unfamiliar with FP in general, or whether it was relatively Clojure specific

22:01 scottj: or braveclojure.com if you must have something free

22:01 andyf: but not necessary

22:01 justin_smith: josiah14: I am one of the Caribou authors, fyi the more common approach in clojure is to use something lighter weight

22:02 josiah14: So I gathered as I browesed through the various frameworks out there

22:02 what's the main reason for that?

22:02 justin_smith: ^

22:03 justin_smith: josiah14: the general clojure preference is to use small composible libs

22:03 caribou is modular, as much as we could make it so, but really we didn't design it to be lightweight

22:03 josiah14: makes sense, I would expect that to be a trend in any functional language, come to think about it

22:03 justin_smith: josiah14: but for the specific niche we developed it for, it can be pretty great if I may say so myself. That niche being making websites where the frontend guys don't do clojure, and rapidly getting an admin / cms up and running where a client or producer can upload content from the getgo

22:04 josiah14: although Haskell frameworks tend to be somewhat sizeable for some reason

22:04 justin_smith: josiah14: in fact in clojure "framework" isn't even a popular term

22:04 josiah14: justin_smith: that sounds like a use-case i would be interested in

22:04 similar to the problem Rails tries to solve, justin_smith

22:05 justin_smith: yeah - it was developed as a replacement for rails that did not require as many server resources, and with a lot less magic

22:05 josiah14: justin_smith: I like the sound of that

22:06 justin_smith: josiah14: cool! I hope you found the docs, they are comprehensive. I am usually in #antler, and sometimes the other devs are too. We were funded by a company we worked at to work on caribou, but that project ended and we went our separate ways, so caribou development is much slower now. But I still work with it and sometimes even make updates.

22:06 josiah14: justin_smith: At first, I was considering using something like MFlow or Yesod, but I want to get this site up and running relatively quickly and easily, and without Heroku being easily accessible with Haskell (I know I could compile a binary, but I don't really want to go down that road), Clojure started looking a lot more attractive

22:07 justin_smith: josiah14: yeah, technomancy has made sure uploading to heroku is easy

22:07 josiah14: another thing is that due to being jvm based, and having really easy interop, it is very easy to deploy clojure webapps to aws elastic beanstalk

22:07 or any other turnkey apache tomcat based thing really

22:09 josiah14: justin_smith: that sounds relatively nice. Although, to hear that development is slowing is maybe a little concerning in that I think this site may potentially have to last for a while and be able to flex and develop

22:09 justin_smith: josiah14: no matter what you use - caribou or not, heroku or aws or whatever else, if you are doing a webapp in clojure you will likely be using ring btw, and it is worth looking at the basics of using ring

22:09 josiah14: cool, I'll definitely be doing that. everything I have seen seems to be built on top of Ring

22:10 justin_smith: josiah14: we've slowed down a bit with new features, but I have had no stability issues with deployed caribou sites, if that helps at all :) but things like liberator are pretty intreguing

22:10 josiah14: justin_smith: I may peek at Liberator. It sounds familiar.

22:11 justin_smith: How is caribou at parallel request processing?

22:11 justin_smith: josiah14: depends on the server implementation, but the throughput is very good (depending partially on how you use /cache the db of course)

22:12 josiah14: I like standalong http-kit a lot

22:12 josiah14: justin_smith: sounds like it's worth at least a download and experimentation

22:12 I must go, but this has been really helpful. Thanks, justin_smith

22:13 justin_smith: josiah14: yeah "lein caribou new" gets you an app that immediately runs and has an admin up to play with

22:13 josiah14: np

22:13 josiah14: err, I mean "lein new caribou"

22:19 oskarkv: gfredericks how does clj-usage-graph/generate normally take? It has like run for a minute and tools.analyzer is still working

22:20 how long*

22:33 gfredericks something called filtered_tree_seq$walk just keeps calling itself :P

22:34 justin_smith: sounds like a cyclical dependency? but technically those aren't allowed in clojure...

23:05 marchdown: I’m learning clojure and I seem to misunderstand I/O facilities. I want to read a number of lines to loop through from stdin, then, well, loop through them. Here’s what I’ve got so far: https://gist.github.com/marchdown/d1388e064570439a39fb but recur says that’s not a tail position. What am I doing wrong?

23:05 oskarkv: marce808 with while you don't need recur, I'm pretty sure

23:05 marchdown

23:05 jeremyheiler: marchdown: I think you want "when"

23:06 not "while"

23:06 marchdown: Didn’t work with when either.

23:06 andyf: also (recur t (dec t)) instead of the recur you have

23:07 oskarkv: marchdown you seem to have one too few ) on the println line

23:07 andyf: wait. You want 2 values in the loop, one an integer and one a string?

23:07 marchdown: I can use lein but I can’t find clojure.jar or clj in my PATH on osx :/

23:07 so how do I test it quickly? I’ve been using lein repl and repl in LightTable.

23:08 andyf: Oh, you want to read an integer from the first line? (read-line) returns a string, not an integer. Need something like (Long/parseLong (read-line)) to assign as initial value to t in loop binding

23:09 marchdown: andyf: how about (loop [t (Integer/parseInt (read-line))] ?

23:09 andyf: and then you want (recur (dec t))

23:09 marchdown: that will work, too, as long as the number fits in a 32-bit signed int, which it most likely does

23:10 recur gives new values for loop names, always in order they are in the loop line, so don't use names in recur

23:10 oskarkv: marchdown you probably want to put the loop in a function that you can call to try it

23:11 then you can call it from the repl

23:12 andyf: oskarkv: Although I'm not so sure reading stdin from REPL always works cleanly, depending on which way you start the REPL

23:13 oskarkv: andyf oh ok, don't usually do that :P

23:13 marchdown: so… how do I run it so that stdin/stdout work as expected?

23:14 oskarkv: marchdown try it from the repl, if that works it's the easiest

23:15 or you could use `lein run` maybe

23:18 andyf: marchdown: I don't do this often, but if you don't mind going through a few setup steps, lein-exec may be useful for creating Clojure programs you run from the command line: https://github.com/kumarshantanu/lein-exec#executable-scripts (that is the middle of the docs, scroll up to start from the beginning)

23:19 Ignore lein 1.x instructions, assuming 'lein version' output on your system says you have version 2.x.y

23:19 marchdown: hmm thanks

23:19 technomancy: stdin should work from lein repl these days

23:20 and most lein-exec usages can be reduced to an alias that points to lein run -m clojure.main

23:21 andyf: technomancy: Doesn't lein run -m clojure.main require running it from inside of the lein project directory?

23:22 oskarkv: marchdown how did you indent the code in that gist btw? It was not "correct", and it would have helped you if it was

23:24 technomancy: andyf: no, it works anywhere now

23:24 marchdown: oskarkv: thanks. I’ve pasted it from an html form. I’ve a version in a lein project locally, which I’m currently trying to massage into executable form.

23:24 technomancy: andyf: provided there are no deps

23:26 marchdown: lein run *arg* seems to work.

23:26 oskarkv: marchdown ok but you were using LightTable? It should be able to indent correctly for you, probably

23:26 marchdown: Now for stdout and when/while/recur stuff.

23:27 andyf: marchdown: while is a loop by itself, so unless you need a nested loop don't do while inside loop

23:28 use if, when, or some variant of those to detect your continue-the-loop condiiton

23:31 marchdown: Nope, neither while nor when work for me here. How is that not tail position?

23:32 andyf: should I then use a let form outside while?

23:32 andyf: is your code still parenthesized as in your first gist?

23:32 marchdown: yes

23:33 andyf: did you read the comment above about incorrect parens?

23:34 what editor are you using?

23:34 marchdown: vanilla emacs and sometimes LightTable.

23:35 andyf: No auto-indenting when you press tab key at the beginning of a line?

23:35 marchdown: ^^ Not sure. I’ve rejiggled it around and rewrote it a couple of times meanwhile. But there’s a general pattern of (let [t (read-me-a-number)] (do-stuff) (recur (dec t)))

23:36 andyf: general patterns are thrown off pretty badly if the parens aren't right :)

23:36 marchdown: :)

23:37 andyf: is it set up to show you the matching paren whenever the cursor is on a paren? Such little niceties are not 100% necessary, but they can improve checking such things 10-fold.

23:37 also setting up auto-indenting for Clojure code can have the same benefits in alerting you to incorrect parentheses

23:37 marchdown: What I seem to misunderstand now is how to keep the scope as narrow as possible, read a bunch of stuff with loops and conditionals.

23:38 Maybe I’m thinking of let-forms wrong.

23:38 ^*about let-forms

23:38 andyf: The general structure of (loop [t <number>] (when (pos? t) <something> (recur (dec t)))) is correct for what you want

23:38 as long as the parens match around the <something>

23:39 marchdown: OK, thanks.

23:39 I see, I have one closing paren missing.

23:39 andyf: if they are off around the <something>, and you make up the difference at the end, then the recur can wind up as a sub-expression of the <something>, and then it likely won't be in tail position.

23:40 right. the suggestions for setting up editor for auto-indenting with tab at beginning of line, and for highlighting matching parens, can help you quickly catch such mistakes.

23:40 TEttinger: andyf: when is wrong there

23:40 marchdown: But shouldn’t recur be inside the inner loop if there are several?

23:40 TEttinger: err maybe

23:40 is it supposed to recur if the number is not positive?

23:40 andyf: So you don't need nested loops for this case.

23:40 amalloy: TEttinger: no, it's a correct translation of the original code

23:40 TEttinger: oh ok

23:41 amalloy: which was (loop [...] (do whatever) (if x (recur)))

23:41 andyf: If you had a case needing nested loops, recur is always matched with the closest loop expression that the recur is inside of

23:43 In Clojure, (loop ...) doesn't loop unless it has at least one occurrence of recur inside of it.

23:43 amalloy: marchdown: also, since you are using emacs anyway, i recommend trying out paredit-mode. it makes it impossible to have unbalanced parens

23:43 it's a bit of an adjustment to get used to, so maybe don't try it if you are already feeling overwhelmed with other stuff, but you should try it eventually

23:44 marchdown: amalloy: I’m procrastinating on paredit because of keymap conflicts. I know that’s the proper way to do work.

23:44 amalloy: interesting. what conflicts?

23:45 [unhelpfully derailing the actual productive conversation]

23:45 marchdown: I’ll get back to you after I waste another evening on this :)

23:46 * marchdown furiously scribbles a note

23:58 marchdown: how do I reload core.clj from lein repl? (use :something)..?

23:59 (use appname.core :reload), is that it, or is there a better way?

23:59 oskarkv: marchdown i like tools.namespace :P

Logging service provided by n01se.net