#clojure log - Aug 09 2013

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

0:02 axle_512: does anyone know if "network channels" for core.async are being developed? Rich hinted at it in his blog post when he introduced core.async.

0:05 xeqi: axle_512: they've been thinking over some different ideas. In the mean time lynaghk has some interesting projects at https://github.com/lynaghk/zmq-async and https://github.com/lynaghk/jetty7-websockets-async

0:06 axle_512: xeqi: thanks

0:06 xeqi: neither of them general "network channels" but possibly useful

0:13 axle_512: xeqi: if I understand correctly, lynaghk's websocket impl lets you use go routines with websocket IO?

0:13 xeqi: if so, that's pretty freakin cool

0:14 xeqi: I think so, but I only saw it earlier and know very little about websockets

0:15 axle_512: I may tinker with it to see if I can understand it better. thanks fro the links.

0:19 Apage43: ooh

0:19 clojurebot: Huh?

0:20 Apage43: I have some aleph/websocket stuff I might see about converting.. though it's really so simple it might not be that helpful

0:23 ToBeReplaced: ,((fn select-by

0:23 clojurebot: #<RuntimeException java.lang.RuntimeException: EOF while reading>

0:23 ToBeReplaced: [f & seqs]

0:23 (when-let [non-empty-seqs (seq (remove empty? seqs))]

0:23 (let [[[x & more] & others] (sort-by (comp f first) non-empty-seqs)]

0:23 (lazy-seq (cons x (apply select-by f more others))))))

0:23 identity [1 3 5] [6 7 9] [2 4 8])

0:23 ,((fn select-by [f & seqs] (when-let [non-empty-seqs (seq (remove empty? seqs))] (let [[[x & more] & others] (sort-by (comp f first) non-empty-seqs)] (lazy-seq (cons x (apply select-by f more others)))))) identity [1 3 5] [6 7 9] [2 4 8])

0:23 clojurebot: (1 2 3 4 5 ...)

0:45 puredanger: axle_512: re network channels for core.async, Tim B has been working on approaches for that

0:46 axle_512: puredanger: thanks

0:50 puredanger: axle_512: it is very challenging (maybe impossible) to match existing async channel semantics when the network and unreliability is in the mix, so the question then becomes what semantics are useful and how do they interact.

0:52 axle_512: puredanger: Does the 'go' language support network channels?

0:53 puredanger: I imagine it's pretty difficult macro coding to get it right.

0:53 puredanger: on the clojure side, that is.

0:53 bbloom: axle_512: they had one at some point, but they cut it

0:54 puredanger: axle_512: the coding is the easy part. understanding what to code in the first part is the hard part.

0:54 s/part/place/

0:54 axle_512: so pretty bleeding edge stuff then. Thanks for the info.

1:00 puredanger: surely

1:05 egghead: bbloom: thanks for the help w/ the core.async stuff, it cleared up a lot

1:05 bbloom: egghead: my pleasure. explaining helps me too!

1:12 ambrosebs: bbloom: have you looked at turning js* nodes in CLJS into AST trees?

1:12 bbloom: ambrosebs: i have a pretty old proof-of-concept branch: https://github.com/brandonbloom/clojurescript/tree/js-ast

1:14 ambrosebs: bbloom: nice

1:15 bbloom: ambrosebs: yeah, i liked it :-) basically just search "js/" in compiler.clj

1:15 ambrosebs: bbloom: I need this done, I will continue your work.

1:15 bbloom: ambrosebs: was dramatically slower, unfortunately

1:15 ambrosebs: ah

1:15 bbloom: in theory, it could be made faster by piping the data structures directly into closure compiler

1:16 but the internal AST for gclosure is an implementation detail & i had to call a bunch of private APIs via reflection

1:16 see also https://github.com/brandonbloom/clojurescript/blob/js-ast/src/clj/cljs/js.clj for the "dsl" of sorts

1:17 ambrosebs: Do you think it's a good idea to convert js* nodes to AST's post-analsis? ie. just before I type check it?

1:17 bbloom: well, parsing JS fragments is a whole-nother problem

1:17 ambrosebs: I figured.

1:17 bbloom: i punted on that & just rewrote usages of js* to work w/ the js ast dsl i made

1:18 very macro-like

1:19 dnolen said that it was ok to break js* though, since it's an impl detail

1:20 i eliminated several uncessary usages of js* in core.clj{,s} but i'm not sure which of them made it back to master

1:20 for example: https://github.com/brandonbloom/clojurescript/commit/3f95b2abbc4294bcbeb46a996becbb08dd21f453

1:21 my first few commits on that branch are illustraitive

1:22 ambrosebs: let me know if there's anything i can do to help! pure functions > printing side effects :-)

1:23 ambrosebs: bbloom: ok, I'll dive in.

1:23 bbloom: the branch is pretty old, lots of stuff has chnaged

1:24 ambrosebs: would you advise starting again with the same approach on top of master?

1:24 bbloom: yeah, i think a manual rebase is probably a reasonable approach

1:24 ambrosebs: ok

1:25 bbloom: my work is in lots of small commits, so you could probably just follow the pattern

1:25 it also hints at how to do the work piecemeal, which was the hard part

1:26 ambrosebs: good

1:27 do you think it will take long?

1:27 bbloom: ambrosebs: gclosure's IR.java library provides a sensible api for building an AST. realistically, there is no need to use the gclosure ast, it was just the shortest path to getting a printer too

1:27 ambrosebs: is that where the reflection comes from?

1:28 bbloom: yeah

1:28 ambrosebs: great

1:28 bbloom: in theory, if we could bipass the printer, then the might be FASTER, but i couldn't figure out how to do that precisely

1:29 also, the gclosure optimizer expects very particularly shaped ASTs

1:29 they have a validator you can run, but i didn't bother b/c the printer seems to be much more permissive than the verifier & optimizer passes

1:29 bypass*

1:29 looks like i worked on it for one long weekend :-P

1:30 ambrosebs: yea, that's promising :)

1:30 bbloom: oh now i remember the bigger issue with bypassing the parser: creating type annotations

1:30 https://groups.google.com/forum/#!topic/closure-compiler-discuss/OEwLWkw4Kug

1:42 ambrosebs: what do you need it for?

1:42 ambrosebs: bbloom: Typed CLJS

1:43 bbloom: glorious.

1:43 the js* form is fucking you up, huh?

1:43 ambrosebs: royally

1:43 I am stuck

1:44 bbloom: could you maybe just add a type paramter to js* ?

1:44 (js* Number "(~{} + ~{})" x y)

1:44 something like that

1:45 * Raynes pokes bbloom with a js*

1:45 ambrosebs: I still want to know what operation is happening

1:45 I might as well break js* properly.

1:45 * bbloom defends Raynes poke with a js*****

1:45 bbloom: ambrosebs: why does the operation matter?

1:45 * Raynes dies from the onslaught

1:46 ambrosebs: bbloom: things like typeof give extra information

1:47 bbloom: ambrosebs: ah. makes sense

1:47 i think eliminating js* is easier than switching to a JS ast

1:48 check out this trick: https://github.com/brandonbloom/clojurescript/commit/335d3e589bf175ff77d31acc36c6174bb54ce567

1:48 ambrosebs: Ok. I've never used js before, so I'm glad you're telling.

1:49 bbloom: basically, that makes js/whatever work like a special form if the whatever is in a list of operators

1:49 only ~ and ^ required special treatment, which i punted on too lol

1:49 ambrosebs: cool!

1:50 do you know how I can get a nice view of all the things you've changed?

1:51 bbloom: learn to git n00b! :-)

1:51 git log `git merge-base master js-ast`..js-ast

1:52 ambrosebs: xD

1:53 bbloom: s/log/diff or difftool, of course too

1:53 ambrosebs: yes of course >.>

1:54 bbloom: so since ~ and ^ were invalid syntax, and js/<< seemed odd given the name clojure.core/bitwise-shift-left....

1:54 i figured that a more robust approach would be to create a js* namespace

1:54 basically a virtual namespace bootstrapped by the compiler which was just a mapping of clojure-friendly-names to operator special forms

1:56 ambrosebs: ok. and you'd have vars like <<, ~ ^ etc?

1:57 bbloom: well yeah, so that commit i just linked you to has a set of vars like that, but since ^ and ~ are invalid identifiers, it would be more like a map '{bitwise-left-shift "<<" bitwise-not "~" …}

1:58 ambrosebs: oh ok, that's your virtual namespace, just a map.

1:58 bbloom: yeah

1:59 anyway, i'm off to bed. good luck & let me know how it goes

1:59 ambrosebs: cya!

2:44 devn: hello all

3:22 callen: devn: hi

3:26 devn: callen: good morning

3:26 callen: what dost thou computeth?

3:29 callen: devn: ring middleware

3:29 nothing interesting

4:08 clj_new_2345: I need to reinsatll ubuntu. I'm at the grub prompt. Is there a way to force grub to boot from the cdrom?

4:08 clgv: clj_new_2345: wrong channel?

4:08 clj_new_2345: yes

4:08 sorry

4:09 habit of auto joining #clojure

4:09 ordnungswidrig: /join #clojure.de

4:37 muhoo: this looks like the long/wrong way: (defn name-to-fn [s] (var-get (resolve (symbol s))))

4:40 clgv: muhoo: vars can be used as functions as well.

4:40 ,((resolve (symbol "inc")) 0)

4:40 clojurebot: 1

4:41 muhoo: oh cool, better thanks

4:52 Hail_Spacecake: I'm trying to install leiningen with the shell script method

4:52 but it seems broken on my system

4:52 does it expect HTTP_CLIENT to already be defined?

4:54 callen: jesus christ that nick

4:55 Hail_Spacecake: like, this script is really broken

4:55 it's trying to call download_failed_messsage before it's defined

4:55 which I don't think you can do in bash

4:55 callen: Hail_Spacecake: ...man, what's with the name?

4:55 Hail_Spacecake: callen what about it?

4:55 callen: Hail_Spacecake: futile?

4:56 Hail_Spacecake: anyway this is the stable version of the script, I can't be the only one with this problem

4:56 futile? not sure what you mean

4:58 schmir: technomancy: installation of the latest leiningen fails for me: /home/tt/bin/lein: line 57: /home/tt/.lein/self-installs/leiningen-2.3.0-standalone.jar.pending: No such file or directory

4:58 is this a known problem?

4:58 callen: Hail_Spacecake: have you tried using refheap to post an error message?

4:58 Also this is the first I've seen of this.

4:59 not that I am an authority or anything, but I lurk enough.

4:59 Hail_Spacecake: I just asked in #leiningen, apparently this just broke

4:59 ah, yeah, there's a commit fixing it

4:59 that is the latest commit

4:59 and an hour old

5:01 hyPiRion: schmir: yes

5:01 I'm working on a temporary fix as we speak

5:01 schmir: ok. thanks!

5:02 hyPiRion: (just need to ensure it works everywhere)

5:55 temp fix: https://github.com/technomancy/leiningen/issues/1279#issuecomment-22384614

5:55 (for Leiningen 2.3.0)

6:02 wei: what's the best way to diff two clojure data structures?

6:14 samrat: wei: you might want to look at clojure.data/diff

6:27 gavri: what's the simplest way to get an instance of the ratio type representing 1/1 ?

6:28 wei: samrat: thanks

6:28 gavri: (rationalize 1) doesn't do it

6:28 neither does (rationalize 1.0)

6:28 but it works for (rationalize 1.5)

6:28 llasram: gavri: Why do you want a Ratio of 1/1 instead of just the (big)integer 1?

6:29 H4ns: is there something better than slime for clojure when one is an emacs user?

6:29 gavri: I've written a recursive method to generate the haromonic series

6:29 I'd like to call (numerator) on the argument to the function

6:29 llasram: H4ns: nrepl.el is the current standard

6:29 gavri: and I'd like to start from 1/1

6:29 H4ns: llasram: thanks

6:29 gavri: and then move to 1/2, 1/3 etc

6:30 it works fine if I start from 1/2

6:30 but I don't know how to start it off from 1/1

6:30 llasram: gavri: You probably want to wrap this in your own function, but: ##(clojure.lang.Ratio. (biginteger 1) (biginteger 1))

6:30 lazybot: ⇒ 1/1

6:31 llasram: Although writing your own wrapper for `numerator` which handles integers is probably ceaner

6:31 cleaner even

6:33 gavri: this breaks too: (numerator (* 2 (rationalize 1.5)))

6:33 doesn't this mean that a lot of code would break quite often?

6:34 if ratios end up with a denominator of 1 in intermediate results of calculations?

6:34 what am I missing here? :-?

6:34 llasram: I honestly don't think people use ratios very often :-)

6:34 It does seem like `numerator` should be identity integers

6:35 gavri: or not at all, it seems :/

6:35 wouldn't it be better if ratios never reduce to integers unless explicitly cast?

6:35 if not, there'll have to be special cases everywhere

6:36 llasram: Just in the arithmetic functions

6:36 Just like `/` on integers results in ratios for non-integral results

6:37 gavri: that's not as bad though, because ratios have more general capabilities than integers, right?

6:37 llasram: Well, except that ratios are much, much heavier-weight on the JVM

6:37 gavri: oh ok, got it

6:38 there has to be a way for the programmer to indicate that they want to work exclusively on ratios though

6:38 so that clojure isn't enthusiastic about converting them back to integers

6:38 llasram: You can reach into the Ratio class directly

6:38 But I really think the solution is that `numerator` should work on integers

6:38 gavri: a more general way than changing #numerator, I mean

6:38 H4ns: i need to write a simple web server that serves statically defined clojure data structures (literals) as json. nrepl.el, http-kit, now i need a json library. any recommendations? it'd be nice if i could generate json in a streaming fashion as i will eventually have to create the json from java instances.

6:38 llasram: gavri: Why more general?

6:38 gavri: ok, thanks, llasram

6:39 for example, what about denominator?

6:39 llasram: H4ns: cheshire is th de facto standard

6:39 H4ns: llasram: thanks again

6:39 gavri: and any functions that get added for ratios in the future

6:39 llasram: gavri: Well, ditto it should return `1` on integers :-)

6:42 Sure.

6:42 gavri: hmm, okay, I'm new to clojure and really have no clue about the philosophies (if that's the right word) of the language

6:43 for now, I'll add custom numerator/denominator functions

6:52 thanks, llasram

7:51 dark_element: cemerick I am using custom repl connect in cljs with austin. https://www.refheap.com/17381 and Also making sure browser-connected-repl-js uses the same repl https://www.refheap.com/17431 I am doing this to send "Browser connected" status from cljs to server. But repl-print is not working with austin. It did work fine with piggieback.

9:20 ToBeReplaced: interleave-by, from last night: https://gist.github.com/ToBeReplaced/6193452

9:20 also how do you get gist to show syntax?

9:22 Anderkent: ToBeReplaced: there's a dropdown saying 'language' when you create a gist

9:22 it also tries to autodetect based on what you type

9:22 (or maybe only based on file extension)

9:23 ToBeReplaced: Anderkent: yeah it wasn't taking, had to change file extension.

9:39 clgv: humm, spotted another asymmetry. why is there no mapv-kv similar to reduce-kv ...

9:40 hyPiRion: clgv: what is mapv-kv supposed to do?

9:41 clgv: hyPiRion: same as mapv but with the optimization of reduce-kv not to create intermediate seqs. well, seems it could be built on top of reduce-kv ^^

9:41 hyPiRion: ah, alright

9:42 clgv: probably thats the reason.

9:43 (defn mapv-kv [f m] (persistent! (reduce-kv (fn [r k v] (conj! r (f k v))) (transient []) m)))

9:43 ah well, a bit typing would be saved ^^

9:49 H4ns: so, as a new clojure user, in order to start some experiments with http-kit and chesire, i create a leiningen project?

9:50 ToBeReplaced: H4ns: sounds good

9:50 H4ns: ToBeReplaced: thanks for the confirmation :)

10:12 abp: technomancy: https://leiningen.s3.amazonaws.com/downloads/leiningen-2.3.0-standalone.jar currently gives Access Denied :/

10:12 clgv: how can I tell leiningen to aot everything for an uberjar? since the jar is started thousands of times I'd want to omit compiling every time

10:18 hyPiRion: abp: https://github.com/technomancy/leiningen/issues/1279 has some workarounds for now

10:22 Anderkent: clgv: doesn't :aot :all work?

10:22 clgv: Anderkent: only for the namespaces of the project

10:23 Anderkent: hm, but that should compile everything referenced by the project

10:23 unless you load libs dynamically, I guess

10:24 clgv: I get no info about the depency namespaces on stdout...

10:24 hyPiRion: Anderkent: It would only make sense for uberjars

10:24 to compile deps aot, I mean.

10:24 Anderkent: look at the classes dir - usually compiling a namespace builds class files for anything reachable from that namespace

10:24 abp: hyPiRion: Thanks!

10:24 Anderkent: hyPiRion: I know, and it's a problem that you can't non-transitively compile

10:25 see http://dev.clojure.org/display/design/Transitive+AOT+Compilation

10:26 clgv: humm interesting. there are a lot of class files in the uberjar in dependency namespaces

10:27 hyPiRion: clgv: yeah, the dependencies themselves may be compiled aot and bundled in a jar.

10:27 clojurebot: clojars deployment is described by _ato in http://groups.google.com/group/clojars-maintainers/msg/4c66317ac3ecd9bb

10:27 clgv: hyPiRion: I just check one dep jar to verify

10:28 hyPiRion: ok. the original dep jar has no classes in it

10:28 so it seems to work with :aot :all

10:28 hyPiRion: clgv: oh, dang, I just opened an issue

10:30 clgv: hyPiRion: well not too bad, since someone with insider knowledge can now confirm that it works like expected...

10:31 Anderkent: Clearly we should go and laugh at you in the issue description for not trying it first. :P

10:32 hyPiRion: Anderkent: This is possibly my third time I've posted a feature request where it was a documentation issue :p

10:32 I'm a bit trigger happy when it comes to issues.

10:35 ambrosebs: Bronsa: hows CinC coming?

10:38 Anderkent: Why doesn't `add-watch` tell you what the current reference state was? There seems to be no way to reliably watch a ref for changes

10:40 say you know what @ref is, and you want to watch for changes. if you (let [known-state @ref] (add-watch ref :key check-change) (check-change :key ref known-state @ref)) you might call check-change twice for the same change, if you do it in reverse order you might miss changes that happened between check-change and add-watch

11:04 shiranaihito: i'm trying to make a custom lein template, but when i use it i get an error saying: "IllegalArgumentException: No method in multimethod 'do-copy' for dispatch value: [nil java.io.File]" .. any idea what's going on? (i'm new to clojure)

11:05 ( the directory for the new project gets created, along with the first source file )

11:05 upwardindex: I'm reading 2 bytes from a RandomAccessFile in 1 call to .read, however the JVM makes two one byte call to linux, any idea how to make it make only 1 call?

11:07 Anderkent: upwardindex: do you know if jvm is explicitly telling linux to read one byte, or if linux is just returning after reading 1?

11:08 upwardindex: Anderkent: It is explicitly telling linux to read one byte

11:08 Anderkent: shiranaihito: it seems you're using clojure.java.io/copy with a wrong set of args.. can you refheap your code?

11:09 shiranaihito: Anderkent: well.. i'm just trying to follow the instructions here: http://yogthos.net/blog/34-Creating+Leiningen+Templates .. but with not much luck

11:09 and as mentioned, i'm new to clojure.. "refheaping" my code, whatever that means, is out of my reach for now :P

11:09 hyPiRion: ~refheap

11:10 aah, clojurebot

11:10 llasram: Come on, clojurebot -- step up

11:10 hyPiRion: https://www.refheap.com

11:10 shiranaihito: :P

11:10 ah..

11:10 hyPiRion: clojurebot: refheap is<reply>https://www.refheap.com/

11:10 shiranaihito: well, there isn't any code outside of what happens in that blog post

11:10 hyPiRion: Oh, clojurebot has died :(

11:10 llasram: Or does it just need a space?

11:11 clojurebot: ping

11:11 hyPiRion: ,(+ 1 2)

11:11 llasram: Oh, dead.

11:11 hyPiRion: boo

11:11 * llasram holds a wake for clojurebot

11:11 shiranaihito: it's probably because of MongoDB.. :p

11:12 hyPiRion: shiranaihito: I wouldn't be surprised actually :p

11:12 futile: flu time

11:12 shiranaihito: :P

11:12 hyPiRion: yeah.. i'm convinced Mongo shouldn't be used, at least for now :)

11:12 Anderkent: shiranaihito: what lein version are you using?

11:12 llasram: shiranaihito: Even if your code is almost just copy-pasted from that blog post, it can still help to post it

11:12 shiranaihito: 2.2.0, apparently

11:12 llasram: Don't be shy! refheap right up!

11:13 shiranaihito: :p

11:15 Anderkent: shiranaihito: I'd start with `lein new template my-lein-template` and see if the default thing works. Then try adjusting it to do what you want and see when it breaks

11:15 shiranaihito: well, i've just been trying to list directories etc that would get created in a fresh project: https://www.refheap.com/b4ea0ef266f47f1ac9adc9b4c

11:15 hyPiRion: shiranaihito: There are some working ones here: https://github.com/stuartsierra/reloaded/blob/master/src/leiningen/new/reloaded.clj and https://github.com/hyPiRion/pirlib/blob/master/src/leiningen/new/pirlib.clj

11:16 shiranaihito: ah, i'll take a look at the working ones

11:16 silasdavis: is there a nicer way to write (map #(% m) [:a :e :c])

11:16 where m is a map

11:16 ?

11:16 llasram: shiranaihito: I think I see your problem -- I believe your one-element vectors need to be just the bare strings

11:16 shiranaihito: oh?

11:16 hyPiRion: shiranaihito: the ["string"] must either be "string" (which will create a directory) or a ["string" (render "string")]

11:17 yeah, the ->files function is a bit weird

11:17 silasdavis: (map m [:a :e :c]) ?

11:17 shiranaihito: hyPiRion: well, i have no idea what's going on there :p just copying that blog post :p

11:18 what does "->" in front of a func name signify?

11:18 hyPiRion: ["string" (render "string")] <-- what would happen here?

11:20 Anderkent: the -> is just part of the function name

11:20 shiranaihito: Anderkent: yes but is it a convention to signify something? like python's "__whatever" for something that's private

11:20 hyPiRion: shiranaihito: actually, it's not that hard to grok. ["string" "file contents"] would create a file named "string" and put "file contents" in it

11:21 Anderkent: it's usually used to imply threading something through a list of calls or conversion into something

11:21 shiranaihito: hyPiRion: ok but how would i know that will happen? :)

11:21 Anderkent: oh, ok

11:23 hyPiRion: shiranaihito: (render "string") takes the file "string" and uses the moustache renderer to work with the contents

11:23 and it returns the contents of the rendering afterwards

11:24 There's a bit more on it here: https://github.com/technomancy/leiningen/blob/master/doc/TEMPLATES.md

11:24 silasdavis: hyPiRion, who'd have thought a map was a function... yeah thanks I knew there was something wrong with that

11:24 hyPiRion: But I wish I could've written more, unfortunately time is not what I have the most of in the world.

11:27 shiranaihito: is mustache considered some kind of standard choice for a templating library for use with clojure?

11:27 or is there something "better"?

11:27 hm.. i think i already asked about this at some poitn

11:27 sakdjds :p

11:28 yazirian: shiranaihito: ->Foo style fn names are typically constructors

11:28 defrecord automatically generates them

11:28 hyPiRion: shiranaihito: It's not better or anything, it's just what the leiningen template system uses.

11:28 shiranaihito: yazirian: constructors? as in, for classes?

11:28 yazirian: i.e. (defrecord Foo [bar]) will cause (->Foo "baz") to work automagically

11:28 that's the convention

11:29 llasram: But to be clear, that's not what `->files` is here

11:29 yazirian: a defrecord? no. a constructor? yes

11:29 llasram: Errr

11:29 yazirian: i.e. from the docstring "Generate a file with content."

11:29 llasram: It instantiates files on disk. It doesn't create file objects. I can see whare you're going, but it's kind of a stretch

11:30 shiranaihito: llasram: you were right btw, thanks! :p

11:30 llasram: See -- always share the code :-)

11:30 shiranaihito: :P

11:30 yeah

11:31 silasdavis: shiranaihito, I like laser

11:32 https://github.com/Raynes/laser

11:32 shiranaihito: silasdavis: ah yes, i believe i heard of that last time

11:32 Anderkent: upwardindex: after some investigations, http://hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/fdd0d43ba0f9/src/share/native/java/io/io_util.c is where the magic happens I think. Can't find where IO_Read is coming from, but it doesn't seem like there's any flag you could set to make it request the 2 bytes

11:34 llasram: Anderkent: But it looks like the readBytes() function will try to read up to `len` bytes at a time

11:35 Anderkent: yes, but he said he asks for 2 bytes there.

11:35 llasram: Right?

11:35 Anderkent: and was investigating why it ends up being two system calls each asking for 1 bytes

11:35 *byte

11:35 (which I assume he knows from strace)

11:37 upwardindex: Well simpler than that I just printk in my character device :)

11:38 Anderkent: ah, then it might be the OS that's asking for 1 byte from you, not java asking linux for 1 byte?

11:40 upwardindex: I'm not aware of any layer that would make that kind of decision, what are you referring to as "the OS"?

11:40 Anderkent: well, I don't know much about how linux implements `read`. It's not unimaginable to me that it doesnt do block reads from character devices ...

11:41 in fact isnt the point of a character device that it only returns a byte at a time?

11:41 nDuff: Anderkent: those details are below the syscall layer.

11:41 Anderkent: where does printk sit?

11:41 I thought it was in the driver

11:41 nDuff: Ahh.

11:42 I wasn't following very closely.

11:42 * nDuff thought this discussion was based on strace.

11:42 Anderkent: so did I initially, but then he says printk in his char device

11:43 rasmusto: an aside: early_printk rules

11:46 upwardindex: Maybe SeekableByteChannel.read is the culprit here

11:47 Anderkent: well, all the java bits should be very easy to debug

11:47 and you can see what the syscall arguments are with dtrace (or strace if you must)

11:48 that should tell you where to look for the issue

11:49 upwardindex: Anderkent: the java bits are easy to debug when you know java ;) anyways, I'll use a workaround for now I don't have the bandwidth, taking notes of all your pointers in the issue, thanks a lot for your help

11:49 Anderkent: you should be able to just attach eclipse or whatever to your process, put a breakpoint in the random access file and watch the arguments

11:50 oh well, good luck :)

11:51 silasdavis: what's the most elegant way to move from a 'maybe nil or [x,y,z]' to a '[] or [x,y,z]'?

11:52 i.e. convert nil to empty list, but otherwise keep list

11:52 Anderkent: list or vector?

11:52 TimMc: or

11:52 Anderkent: nil is an empty list

11:52 llasram: silasdavis: Most functions slet you treat `nil` as an empty sequence. Why do you find you need to?

11:52 Anderkent: Well, not quite: ##(= nil ())

11:52 lazybot: ⇒ false

11:52 Anderkent: that just means = is broken :)

11:53 TimMc: silasdavis: (or foo [])

11:53 upwardindex: silasdavis: (or mystuff [])

11:53 llasram: Anderkent: Why do you say that?

11:53 TimMc: No, the seq abstraction is broken.

11:54 Anderkent: i'm half kidding, I find nil punning very annoying most of the time. But it seems it's here to stay, so let's pretend it's consistent

11:54 TimMc: () should always be the empty seq; nil-punning is cute but problematic.

11:54 abp: always sequing for nil

11:55 Anderkent: ##(seq? (seq nil))

11:55 lazybot: ⇒ false

11:55 Anderkent: #thiscljlife

11:55 silasdavis: I sort of want a cons or a conj that will treat nil as an empty sequence

11:56 Anderkent: huh?

11:56 ##(cons 1 nil)

11:56 lazybot: ⇒ (1)

11:56 Anderkent: oh you mean you want to keep it

11:57 silasdavis: ##(cons nil [3])

11:57 lazybot: ⇒ (nil 3)

11:57 silasdavis: ##(cons [3] nil)

11:57 lazybot: ⇒ ([3])

11:57 Anderkent: well cons takes the thing to add first and the sequence second, that all seems reasonable to me

11:58 silasdavis: so I need the former to give me (3)

11:58 Anderkent: huh?

11:58 cons is not concat :P

11:58 silasdavis: ##(conj [] [3])

11:58 lazybot: ⇒ [[3]]

11:58 silasdavis: ##(concat [] [3])

11:58 lazybot: ⇒ (3)

11:58 silasdavis: ##(concat nil [3])

11:58 lazybot: ⇒ (3)

11:58 silasdavis: Anderkent, concat.. thanks

12:04 Is there a nice way to move from a 'maybe x or [x]' to '[x]'?

12:05 i.e. treat a single element as a singleton..

12:06 in ruby you might do something like [val].flatten

12:07 Anderkent: uh, it's doable but I wouldn't recommend it. Leads to really weird behaviour when someone passes a list as x for example

12:07 silasdavis: but that is less acceptable here

12:07 yes

12:08 Anderkent: better have a separate function that only takes a single arg and wraps it in a list then calls the main function that always takes a list

12:08 then your api is cleaner

12:09 silasdavis: so nothing better than #(if (coll? %) % [%])

12:10 Anderkent: Not sure if coll? is the right predicate there

12:11 silasdavis: hm no it's not, because it's true for a map

12:11 what can I use that will get all list types...

12:12 Anderkent: you'll have a problem with strings too

12:12 mattmoss: seq? or sequential?

12:13 Anderkent: sequential? does it I guess ... But I still think it's a bad idea :)

12:13 mattmoss: ##(seq {:a 1 :b 2})

12:13 lazybot: ⇒ ([:a 1] [:b 2])

12:13 silasdavis: that looks like it's about right

12:13 Anderkent, why?

12:14 Anderkent: (defn do-foos [foos] ...) (defn do-foo [foo] (do-foos [foo])) is just much cleaner

12:14 as I said

12:14 invariably leads to confusion

12:14 like -> does it

12:14 silasdavis: you might be right

12:14 Anderkent: and it always sucks

12:14 silasdavis: -> ?

12:15 Anderkent: the threading macro ->. At least for it the allowed syntax is very restricted and the automagic list wrapping only happens for a single symbol... But still a pain and common source of confusion

12:16 mattmoss: ##(seq nil)

12:16 lazybot: ⇒ nil

12:16 mattmoss: nope

12:16 rasmusto: and -> leads to ->> leads to -<>-> or w/e

12:20 silasdavis: where does the confusion come from?

12:21 justin_smith: (-> foo bar) is the same as (-> foo (bar))

12:21 Anderkent: but different from (-> foo ((bar))) :P

12:21 justin_smith: but (-> foo ((bar))) is a different thing altogether

12:21 jynx

12:21 Anderkent: ninja

12:21 justin_smith: and they you have to do things like (-> foo (#(bar nil %)))

12:22 just to change argument ordering

12:22 and the extra paren wrapping is odd

12:22 since #(bar nil %) is not necceessarily returning a function of no args, and that returned value is not being called

12:22 inconsistent

12:24 gfredericks: (as-> x <> ...)

12:25 Anderkent: (<<- ...) is amazing too

12:27 silasdavis: so would you completely avoid them?

12:30 Anderkent: When designing a function I'd avoid taking a 'list-or-single-element', instead offer two functions one taking a list and the other taking a single element

12:31 the caller will always know which one it wants to call anyway

12:33 TimMc: duck-wrapping

12:43 Anderkent: if it doesn't quack, wrap it in a duck? Gross imagery.

12:44 Raynes: Anderkent: lol

12:45 Chousuke: there's usually no reason to even provide the 1-item function unless it's the 90% use case or something :P

12:45 Anderkent: indeed. And even then, if it's only one sequence, consider varargs

12:46 hm actually that might not work for longer sequences, nvm that

12:46 Chousuke: at least in a language where the difference between a sequence and a single element is two characters.

12:51 silasdavis: yeah I've ditched the single item thing

12:52 whats the best way to go from [x y z] to {x (f x) y (f y) z (f z)}?

12:53 Raynes: (into {} (for [[k v] a-map] [k (f v)]))

12:53 Anderkent: what

12:53 no

12:53 Raynes: Oh, that was unrelated.

12:53 Sorry.

12:53 Anderkent: (into {} (map (juxt identity f) my-vector))

12:53 Raynes: You're a bad person.

12:53 Anderkent: xP

12:53 sorry, that came out harsher than I intended

12:54 justin_smith: for extra win, (def identity id)

12:54 Raynes: (mapcat (juxt identity f) l)

12:54 silasdavis: ^

12:55 justin_smith: Raynes: I think the into {} version was actually right

12:55 Raynes: You didn't seem to want a map.

12:56 If so, then indeed.

12:56 Anderkent: (into {} ) always looks strange to me

12:56 there should be an easier way of converting a maplike seq back into a map

12:59 justin_smith: (def as-hash (partial into {}))

12:59 silasdavis: thanks

13:00 why do functions in clojure core tend to get defined for 0, 1, 2, 3 arguments before being defined for arbirtrary args?

13:00 (such as juxt)

13:00 justin_smith: I would hazard a guess it is for performance reasons

13:01 Raynes: It is.

13:01 hyPiRion: yup, most likely perf reasons

13:01 silasdavis: I assumed that must be the case

13:01 do you understand why?

13:01 Raynes: It is definitely performance reasons, for I know this for a fact.

13:03 Anderkent: silasdavis: I'd guess if the compiler can count the arg number and find the right implementation statically it saves a layer of indirection on runtime

13:03 Raynes: In a lot of cases it's faster to take and work with a specific argument count than to seq them up and then unroll them, etc.

13:03 justin_smith: is it about avoiding the overhead of implicitly creating the sequence for the varargs, only to immediately destructure them?

13:03 answered my question just before I asked it, thanks

13:03 Anderkent: yeah that sounds reasonable too

13:04 justin_smith: technically creating a seq and then destructuring it is a layer of indirection over the arguments, so you were on the right track

13:05 silasdavis: Anderkent, your first reason is a bit circular; the only reason there are multiple implmentations is give essentially identical implementations of lower arity

13:06 or do you mean the functions are possibly called from that have meaningfully different implementations

13:07 anyway the seq thing makes sense

13:07 Anderkent: silasdavis: for functions where the low arity version does not call the high arity version I was guessing that calling a 2-arg function is cheaper than calling a var-arg function

13:08 does that address your point or am i misunderstanding/

13:09 afaik calling a vararg funciton is done by a wrapper that basically does (switch (count args) (case 1 (call-arity args[0])) (case 2 (call-2-arity arg[0] arg[1])) etc.

13:09 which is why there's a max count to varargs

13:10 squidz: cemerick: I am using your nice austin library and wondering how you normally restart your jetty server while developing. May be more of a compojure question.

13:10 cemerick: squidz: I don't

13:10 Why do you need to restart jetty?

13:10 justin_smith: Anderkent: I thought it created a seq, which is why kargs work with varargs

13:11 squidz: because I am making changes to my static resource and need it to be reloaded which it seems not to be doing

13:11 my index.html

13:11 justin_smith: you just reload the resource

13:11 Anderkent: justin_smith: yeah you're right, it's a switch on the count of a seq then ifn.invoke(arglist.first(), arglist.next().first ...)

13:11 justin_smith: no need to restart the server

13:11 Raynes: cemerick: http://cdn.memegenerator.co/instances/600x/40437985.jpg

13:11 Anderkent: and of course I ment max arity of function, not max count of varargs

13:12 squidz: so how do I reload it then?

13:12 Anderkent: wait, (merge a-map b-map) is the same as (conj a-map b-map)

13:12 how come?

13:12 justin_smith: squidz: use a middleware that notices when a resource changes, or at dev time you can just uconditionally load from disk it on every request

13:12 Anderkent: weird.

13:13 cemerick: squidz: what route do you have for serving your static resources?

13:13 Raynes: s/always/ever need to/g

13:14 squidz: cemerick: here is what it looks like. Very simple https://www.refheap.com/17437

13:14 cemerick: squidz: yeah, that should never be a problem. Maybe your browser is caching? Shift-reload?

13:14 xeqi: squidz: is page the same as in the sample app?

13:14 squidz: where page was the enlive template that you provided in your documentation

13:15 cemerick: squidz: oh, there you go; you need to load the clojure namespace where the template is loaded by enlive

13:16 xeqi: I switched mine to laser to avoid the template caching

13:16 squidz: after reavaling the whole core.clj with the enlive template inclueded, it should work

13:17 but it doesnt

13:18 here is the whole core.clj https://www.refheap.com/17438

13:22 okay nvm I had several nrepl sessions open and I was eval'ing in the wrong session

13:23 cemerick: squidz: :-D sorry, man

13:23 squidz: yeah sorry for the silly question thanks anyways for the help

13:24 tieTYT: can you guys help me with something? I couldn't figure out how to implement step 4 of this answer in a functional way. How would you do that? http://gamedev.stackexchange.com/a/6045/31177

13:25 it's a simple for loop that goes: R = (some random int); T = 0; for o in os (T = T + o.w; if T > R then return o)

13:25 Anderkent: well, you can do it with (loop) obviosuly, but that's not very nice

13:25 tieTYT: right I wanted to know how to implement this functionally

13:25 using map and reduce, etc.

13:26 justin_smith: for that sort of short circuiting, you could use iterate and drop-while the end condition is not met, then take the element that meets the condition

13:27 Anderkent: justin_smith: the problem is that the condition is modified in every loop iteration

13:27 justin_smith: then you make iterate return the variables which create the condition

13:27 Anderkent: right

13:27 yeah that makes sense

13:28 tieTYT: but won't drop while give me the number? I'm trying to get the object

13:28 justin_smith: ((comp :answer first) (drop-while (comp not :done) (iterate (fn []) {:done false :conditions [] :answer nil})))

13:28 something like that

13:29 basically everything that would be a variable in the mutable version is a key in a map passed through iterate

13:29 Anderkent: yeah but that's not very nice either

13:29 justin_smith: but it is functional

13:30 tieTYT: sounds like that algorithm is tough to do in fp

13:31 justin_smith: nah, not hard, just ugly

13:31 Anderkent: well that particular algorithm is very iterative

13:31 I'm trying to think of a prettier one that would do the same

13:31 justin_smith: isn't there a form of reduce that can just short circuit at some step?

13:32 hiredman: iterate + take-while

13:33 ToBeReplaced: is there anything I should know about using Thread/sleep inside of clojure.test?

13:33 tieTYT: see the problem I think with reduce is

13:33 hiredman: justin_smith: reduce can short circuit, it is new feature

13:33 justin_smith: ahh, that is the clean way to do it then, if you can use the new clojure

13:33 where are the docs on that?

13:34 tieTYT: actually nm, I don't know. Where I got stuck is, "this is easy to figure out when to stop using a reduce, but I want to return the o type and the memo would need to be an int before that. I must be doing something wrong"

13:34 i'm not sure if that thought process was clear

13:36 anyway I'm really using JS and underscore.js to write this code. underscore doesn't have an iterate

13:36 so I just did it iteratively :T

13:41 noonian: its easy to implement recursively :P

13:42 xeqi: ,*clojure-version*

13:42 clojurebot: are you broken?

13:44 &*clojure-version*

13:44 lazybot: ⇒ {:major 1, :minor 4, :incremental 0, :qualifier nil}

13:45 tieTYT: noonian: can you show me?

13:45 xeqi: surprised hes still on 1.4

13:46 justin_smith: xeqi - I think it is intentional that clojurebot and lazybot are the two most recent versions

13:46 xeqi: tieTYT: (let [r 7] (reduce (fn [t [i w]] (let [t (+ t w)] (if (< r t) (reduced i) t))) 0 [[0 1] [1 2] [2 3] [3 4] [5 6]])) will work in 1.5

13:47 justin_smith: ahh, that is how to get the short curcuit

13:47 xeqi: justin_smith: ^ (doc reduced) is all I can find about the "short circuit"

13:47 justin_smith: I tried to google and found nothing

13:47 yeah, but how was I to know reduced was the thing to look for?

13:47 tieTYT: cool I'll have to check that out

13:47 why DO you need to short circuit? Couldn't you just leave the memo as it is for the rest of the reduce?

13:48 xeqi: unfortuantly.. wait for the irc collective?

13:48 justin_smith: seems silly

13:48 that is, reducing on the rest of the collection when you already have the asnwer seems silly

13:48 also, what if you wanted to reduce on an infinite lazy list?

13:49 tieTYT: fair points

13:49 xeqi: tieTYT: the memo is t until the condition, then switches to i. The rest of the computation needs to know not to treat it as t then

13:49 which can be done by using memo of [t i] or a map or such

13:49 tieTYT: ok yeah. See that wouldn't conceptually be an option in haskell then

13:49 you couldn't even consider this as an approach, right?

13:50 sorry, brb

13:50 noonian: tieTYT: in JS? or clojure?

13:51 ,(doc reduced)

13:51 clojurebot: "([x]); Wraps x in a way such that a reduce will terminate with the value x"

13:51 noonian: huh, thats seems very useful

14:04 mdrogalis: Hey sritchie. :)

14:04 sritchie: yo

14:22 tieTYT: noonian: either. I could probably understand the JS better though

14:29 callen: why does ritz only support breakpoints for slime?

14:31 mthvedt: is it safe to write code that relies on the #= reader macro

14:31 nifff: hello room:) ,how slower are immutable data stractures?i made a program that has a lot of large vector and maps changes and its slow,maybe its my implementation or it is because of immutable data structures?

14:32 i love clojure,just worrying if its slow...

14:32 noonian: tieTYT: here's a recursive version, it uses underscore and is untested

14:32 tieTYT: http://pastebin.com/k0wxW3Ja

14:32 TimMc: mthvedt: Safe as in security or safe as in future-proof-ness?

14:33 noonian: nifff: are you sure its not just slow to startup because of the jvm startup time? they should be pretty efficient in general

14:33 TimMc: mthvedt: And is it your code, or data you are reading?

14:33 mthvedt: TimMc: future-proof-ness

14:34 noonian: tieTYT: oops, I had 0.w in there instead of o.w but you get the gist

14:37 nifff: i am thinking that maybe the garbage collector make my program slower,because i use heavy data stractures

14:37 gfredericks2: dericks

14:37 noonian: nifff: is it still slow if you call your function from the repl?

14:38 nifff: yes i use the repl,

14:38 the similar program in javascript its 10x fastewr

14:38 noonian: what does the #= reader macro do?

14:38 ,#=(println "test")

14:38 clojurebot: #<RuntimeException java.lang.RuntimeException: EvalReader not allowed when *read-eval* is false.>

14:38 noonian: ,#=17

14:38 clojurebot: #<RuntimeException java.lang.RuntimeException: EvalReader not allowed when *read-eval* is false.>

14:38 gfredericks: noonian: it evals the contents at read-time

14:39 noonian: gfredericks: ah, thanks

14:41 tieTYT: noonian: ah ok, I like that. Thanks

14:41 noonian: you might want to answer that here: http://stackoverflow.com/questions/18152343/how-can-this-imperative-code-be-rewritten-to-be-more-functional

14:41 noonian: tieTYT: no problem, be careful if you have a lot of objects though because you could potentially blow out the stack

14:41 nifff: does anyone know how much slower are persistent data structures?my programa is 8x slower than a javascript one,can this caused by the data structures being immutable?

14:42 noonian: nifff: can you post a code example of what you are doing thats slow?

14:42 nifff: i use large vectors and hash maps,and i assoc values

14:42 all the time

14:43 dnolen: nifff: it just depends, you may be able to use transients in hot spots. Still if performance is critical, you can write CLJS so that it maps directly to the JS you would write.

14:46 nifff: if you want specific performance advice you will probably need to paste your code somewhere

14:53 [1]nifff: -

14:56 nifff: https://www.refheap.com/17443

14:56 if anyone have a llok

14:59 dnolen: nifff: oh oops, I thought this was CLJS, but not matter, that's pretty unidiomatic looking code.

14:59 s/not matter/no matter

15:00 nifff: atoms won't make it any faster, paste your version sans atoms

15:00 callen: dnolen: you can write Fortran in any language.

15:01 dnolen: nifff: also are you using leiningen?

15:01 nifff: yes i use counterclockwise

15:02 dnolen: nifff: you may need to set explicit server settings in your project.clj since Lein uses bad defaults

15:02 or used to (not sure about 2.3.0)

15:02 xeqi: for some value of "bad"

15:02 dnolen: xeqi: bad for benchmarking

15:02 xeqi: or profiling

15:03 nifff: https://www.refheap.com/17444

15:03 dnolen: nifff: that code also looks like it needs work :)

15:04 nifff: its a freak :)

15:04 * technomancy graphs the number of lein users who complain about runtime performance vs number who compare about startup times

15:04 technomancy: .|

15:04 dnolen: nifff: make sure JVM -server settings is enabled

15:04 nifff: how to change this?

15:04 technomancy: dnolen: -server is actually impossible to turn off these days

15:04 unless you're running a 32-bit JVM

15:04 dnolen: technomancy: not on OS X

15:05 technomancy: wow, they still haven't made the jump yet?

15:06 nifff: the question i have is it the persistent data or my code?how slower are persistent data? 2x 4x 8x :)

15:06 dnolen: technomancy: all I know is that I need to enable -server explicitly in Lein now

15:07 nifff: there's too much code to tell, but different data structures have different profiles - you can benchmark different cases yourself :)

15:07 noonian: nifff: I would guess it's the code, but I can't really read the code so I'm not sure

15:07 nifff: thanks people for trying,when you have a large data structure with a lot of assocs what you use?

15:08 i used vectors and maps

15:08 noonian: well, you can use a single assoc to put multiple keys in at the same time

15:08 I'm not sure what you mean lots of assocs

15:08 dnolen: nifff: vectors and maps, but it looks like you're trying to do Binary Decisions Diagrams with persistent data structures?

15:09 nifff: yes thats i am doing binary decision diagrams

15:09 i made the program its ready but slow

15:09 TimMc: mthvedt: I think #= will probably stick around for a while, but I'd bet it is undocumented so that people won't use it...

15:09 dnolen: nifff: I don't really the benefit of immutable data here when speed is the goal usually with BDDs

15:10 nifff: what data structure to use?

15:10 dnolen: nifff: I'm assuming you're using arrays in Java?

15:10 nifff: use them in Clojure

15:11 nifff: ok i will use java arrays,and i will compare the perfomance,thanks

15:11 bye room:)

15:11 dnolen: nifff: make sure to use (set! *warn-on-reflection* true)

15:11 nifff: w/ arrays you have to be careful w/ type hinting

15:11 nifff: ok but i dont know what that means :)

15:12 i will read java interop first

15:12 dnolen: nifff: bingo :)

15:21 jcromartie: Is Aleph (still) the best way to write a simple TCP server in Clojure?

15:21 I feel like it's gotta be

15:22 ztellman: arguably just using java sockets could be simpler, for some definition of simple

15:22 but aleph is more idiomatic

15:23 futile_: pst ztellman what OS you on

15:23 ztellman: os x

15:23 * futile_ actually has strep, not the flu

15:23 futile_: ztellman: use any window manager?

15:23 ztellman: nope

15:23 futile_: oh wait this is off topic

15:24 technomancy: jcromartie: there's no one right answer; it depends on the shape of your problem.

15:24 jcromartie: technomancy: I know you've got a lib

15:25 futile_: anyone used Instaparse?

15:25 technomancy: not really

15:26 jcromartie: if you're mostly just shuffling bytes around you'd be better served with Aleph. if your connections end up doing substantial work on the same node, (so that each node can't service more than a couple thousand connections at a time) use raw sockets.

15:27 s/just //; didn't mean to trivialize it

15:27 ToBeReplaced: jcromartie: i use (cl)jzmq for persistent tcp

15:27 ztellman: feeling very trivialized over here :)

15:27 clojurebot: No entiendo

15:27 jcromartie: ztellman vs technomancy: FIGHT

15:27 TimMc: clojurebot: You *wouldn't* entiendo.

15:27 clojurebot: I don't understand.

15:28 technomancy: jcromartie: honestly if you need it to be fast you should just use node.js, duh

15:28 callen: apparently my entire career has been just shuffling bytes around

15:28 TIL

15:28 TimMc: "Chris Allen: Electron pusher"

15:28 technomancy: http://p.hagelb.org/async.jpg

15:28 jcromartie: technomancy: I don't need web scale or big data

15:28 TimMc: That's your business card right there.

15:28 jcromartie: :|

15:28 :P

15:30 technomancy: jcromartie: I spun the server-socket lib out of old monolithic-contrib but don't really have any intention of using or maintaining it

15:30 jcromartie: yeah

15:30 technomancy: should probably mention that in the readme

15:30 jcromartie: I see that. It's just there, which is fine. I'm glad it's that simple.

15:31 but let's say you wanted to write a MUD

15:31 (I'm trying it right now, with Aleph)

15:32 technomancy: an excellent! ideahttps://github.com/technomancy/mire

15:32 jcromartie: everybody loves MUDs

15:32 technomancy: err--an excellent idea

15:45 jcromartie: ztellman: so do you see Lamina being built on core.async in the future, or do you see core.async taking the place of Lamina in projects like Aleph

15:45 ztellman: also, are you completely sick of this question yet?

15:45 ztellman: jcromartie: I see Aleph being equal-opportunity w.r.t. stream representation

15:47 probably by default the channels will be core.async, since that's where the momentum seems to be, but Lamina and core.async are different enough in their goals/implementations that they can coexist

15:50 ToBeReplaced: ztellman: how are their goals different?

15:51 ztellman: ToBeReplaced: see the comments at the bottom of http://clojure.com/blog/2013/06/28/clojure-core-async-channels.html

15:51 ToBeReplaced: thanks

15:53 ztellman: it may turn out that Lamina's unique qualities only matter to me and a few other people, but they help with my day-to-day job, so I think I'll keep it around for a bit longer

15:55 ToBeReplaced: i haven't had the pleasure to work with Lamina yet -- i do have the need to treat queues as streams often though

15:56 ztellman: ToBeReplaced: I find it to be a nice way to think about/process streams of data

15:56 but it's kind of a sprawling mess of functionality right now

15:57 I'm in the process of trying to extract functionality that doesn't need to be coupled to its particular stream representation

15:57 see https://github.com/ztellman/narrator among others

15:58 ToBeReplaced: interesting; i'm interested in the stream operators over channels for times where blocking is acceptable

15:59 map* etc. over channels being populated elsewhere -- that sort of thing is really clunky over BlockingQueues

16:00 ztellman: yeah, also bifurcation of queues

16:05 pbostrom: +1 to lamina, nice library, even if it was crappy, the viz stuff would make up for any short comings

16:06 ztellman: pbostrom: thanks, the viz stuff is in its own library too, now :)

16:06 ToBeReplaced: splitting a lazy-seq is weird too though

16:07 ztellman: ToBeReplaced: splitting a lazy-seq is risky, the consumers may go at different rates and cause a memory leak as a result

16:07 you want the consumers to be coupled

16:07 or at least aware of each other

16:08 ToBeReplaced: you have related problems splitting off of queues though if one queue gets filled up

16:09 i think splitting is necessarily hard -- no matter how you do it you need to deal with the different consumers

16:12 ztellman: ToBeReplaced: that's because the topology of the queues is implicit; there's no way to know when a given message has cleared your dataflow

16:12 ToBeReplaced: i take it back -- you can at least handle a memory leak b/c you can block at the site of the split and prevent A from getting any more action until B does its job

16:13 ztellman: yes, though that has the TCP bufferbloat issue of waiting for all the queues to fill up before you get any backpressure

16:13 ToBeReplaced: yeah, generates thunder hard and fast

16:14 ztellman: an interesting property in Lamina is that if a message lands in a queue, it returns a promise representing the consumption of the message

16:15 if it travels through multiple queues, it yields a promise that yields a promise that yields...

16:15 but this allows you to actually know when a message has actually cleared the topology, including actually clearing the TCP write buffer, etc.

16:16 so you know exactly how much is in flight at any given time

16:19 ToBeReplaced: when would you travel through multiple queues without coming off? i would have assumed that coming off would cause the promise to yield

16:20 trying to understand how that's different from asking a queue "hey what's your size, and how many you got?"

16:22 ztellman: ToBeReplaced: when you have multiple queues pipelined together

16:22 which happens reasonably often, when it's easy to compose operators together

16:22 so there's a difference between clearing the queue(s) closest to you, and clearing the entire topology

16:23 to be fair, this may not be significantly better than just using blocking queue semantics

16:23 but it's an interesting space to experiment in

16:23 ToBeReplaced: ah, so it's the operators responsibility to relay the messages back?

16:24 ztellman: kinda, it's mostly implicit

16:24 all channels have queues, which are bypassed if there's something downstream

16:25 if you're doing something clever like batching or flattening streams messages, you need to correctly handle the return values you get from propagating them downstream, but the provided operators do that for you

16:26 ToBeReplaced: okay

16:37 qed: I want to make a function that is called like: (foobar :a 1 :b 2) -- how do people typically write the definition so the args can be treated like a map?

16:38 llasram: qed: ##((fn [& {:as args}] args) :a 1 :b 2)

16:38 lazybot: ⇒ {:a 1, :b 2}

16:38 qed: thanks llasram

16:49 upwardindex: Is there any other way to write foo/bar ?

16:50 I mean (foo/bar)

16:50 TimMc: qed: You don't.

16:50 It's really irritating to call such functions, especially if you want to apply args to them.

16:51 Instead, what you want is (fn [foo bar & [{:keys [a b]}] ...), which is called with an optional final map argument.

16:52 llasram: upwardindex: In what sense?

16:53 upwardindex: llasram: trying to do something like this https://www.refheap.com/17447

16:54 but ~module/initialize is trying to ~ "module/initialize" instead of only "module"

16:54 llasram: upwardindex: Huh. Well, you can do `~(symbol (name module) "initialize")`

16:55 I'm not sure how advisable that is though -- definitely not a common pattern

16:57 upwardindex: llasram: yes I see, there might be something else i can do if I approach the problem differently

17:03 How could I make a function that receives a list of namespaces and calls the foo method in each one

17:05 llasram: upwardindex: Well, exactly the same way as ^^

17:05 It's the idea of having the particular name of a function embedded in a macro which isn't a common idiom

17:06 noonian: hmm, just going off the docs of in-ns, I might try something like (binding [*ns* namespace] (foo)), but I haven't had a use case for that and not sure how that'd work

17:06 ,(doc in-ns)

17:06 clojurebot: "([name]); Sets *ns* to the namespace named by the symbol, creating it if needed."

17:06 llasram: upwardindex: Oh, you said a *function*

17:06 in-ns won't do what you want, because of how dynamic vars interact with compliation

17:07 `resolve` is the thing to look at if you can't be disuaded

17:07 noonian: yeah, in-ns seems to rebind the var at the top level, but a local binding might work using binding

17:07 ,(doc resolve)

17:07 clojurebot: "([sym] [env sym]); same as (ns-resolve *ns* symbol) or (ns-resolve *ns* &env symbol)"

17:07 llasram: Oh, `ns-resolve` right

17:07 noonian: :D there you go

17:08 upwardindex: noonian: thank you!

17:08 I guess the cleaner way would be to define an interface?

17:09 llasram: Or just let users pass in a function to call?

17:09 noonian: np

17:10 yeah, a list of functions (from w/e namespace) instead of a list of namespaces is how I would go about it

17:11 upwardindex: llasram: I might be over-refactoring it's just that the code is quite redundant

17:11 I'll medicate on that, thanks guys!

17:12 llasram: nice

17:13 ToBeReplaced: in Leiningen, can dev profiles specify environment variables?

17:15 llasram: ToBeReplaced: If you're referring to https://github.com/weavejester/environ and lein-environ, then yes

17:16 Leiningen has no builtin to set arbitrary environment variables via project.clj

17:16 s,builtin,built-in way,

17:18 ToBeReplaced: llasram: what about jvm-opts? i want that "lein test" runs with something, anything, different from "lein run"

17:18 qed: Can I programatically call methods like: (for [meth '(.fooBar .barBaz)] (meth "ABC"))?

17:18 ToBeReplaced: preferably lein run != lein repl != lein test

17:19 llasram: ToBeReplaced: You can set JVM properties via `:jvm-opts`, if that's what you actually need. People use them similarly to environment variables, but they aren't the same thing :-)

17:19 ToBeReplaced: qed: you'd have to create anon functions aroud them (for [meth [#(.fooBar %) #(.barBaz %)] (meth "ABC"))

17:19 technomancy: ToBeReplaced: the repl and test tasks both check for profiles named :repl and :test respectively

17:19 qed: ToBeReplaced: Sounds like a job for a macro

17:20 ToBeReplaced: jvm-opt would work for me; i don't grok leiningen profiles -- can i specify jvm-opts within a profile, and it'll get merged with the top level jvm-opts?

17:20 llasram: quackv4: Not really, actually. There's `memfn` from the olden-days, but the #(...) syntax is shorter, more flexible, and allows you to provide type hints

17:20 qed: i think you meant me llasram

17:21 llasram: hah!

17:21 You are correct

17:21 technomancy: ToBeReplaced: :jvm-opts from profiles will get appended to :jvm-opts in defproject top-level

17:21 ToBeReplaced: llasram: technomancy: thanks, sorted

17:21 technomancy: ToBeReplaced: it won't be "merged" in a key-value sense, but it will be combined

17:21 ToBeReplaced: right

17:21 tbaldridge: dnolen: JIRA is giving me problems atm, but that set! async bug is fixed.

17:22 qed: llasram: you say memfn from the olden days like it's a bad thing

17:22 dnolen: tbaldridge: excellent!

17:22 llasram: qed: It's unofficially deprecated. It probably wouldn't have existed if the #(...) had appeared earlier

17:23 (is my understanding, anyway)

17:23 dobry-den: i'm writing simple ring middleware to redirect `/hello` -> `/hello/` but not `/hello.jpg` -> `/hello.jpg/`. Would it be sufficiently robust to just look for a trailing extension to see if i don't need to redirect?

17:23 technomancy: I like memfn =(

17:23 qed: rich doesn't like it though

17:23 llasram: I bet you also like kittens! And sunshine! Ugh. What kind of monster are you?

17:23 technomancy: rawr

17:24 I'm not totally clear why bare .methodCall symbols couldn't be implicitly memfn'd

17:24 callen: I'm puzzled by memfn when we have nice function literals.

17:24 bbloom: technomancy: has to do with overload resolution

17:25 technomancy: bbloom: and probably because you wouldn't want that when it's in the call position

17:25 llasram: What about #.method as reader syntax for memfn?

17:25 technomancy: and caring about call position is tacky

17:25 callen: fewer tokens

17:25 bbloom: just like how you can't take the value of a macro without applying it to forms, you can't take the value of a method call without applying it to argument types

17:25 callen: technomancy: what's the matter, don't like #(%)!@@@@@ ?

17:26 technomancy: callen: aren't you CL types supposed to complain about all the extra syntax clojure has? =)

17:26 qed: llasram: so what i want to do is take a seq of java methods, all of which take 1 argument. I want to generate fn names like "foo-bar?" from "isFooBar". Is that doable?

17:26 callen: technomancy: one would almost think you like Lisps.

17:26 technomancy: yes, that's what I'm lampooning.

17:26 technomancy: I prefer words and parens and little else, although vectors have won me over.

17:26 technomancy: binding: it's not the same as calling.

17:26 #truefacts

17:27 llasram: qed: That's more usefully-doable, because you can do all the mangling at macro-expansion-time and even provide sane type-hints

17:27 ToBeReplaced: qed: yeah, macro-it-up

17:28 harder to get the method names though

17:28 bbloom: technomancy: but to fully clear up the auto memfn-ification of .methodCalls: it's doable if the compiler was defunctionalizing

17:28 technomancy: that is, all higher order operations would be inlined

17:28 ToBeReplaced: at least, hard to do it sensibly (and do all the right things around overloading)

17:28 bbloom: technomancy: but since functions are reified into IFn instances, then we can't do it, except as a potential optimization

17:29 technomancy: bbloom: yeah, I'm OK with "it would introduce a bunch of special cases resulting in unpredictable behaviour" I gueeeeeeess

17:29 qed: llasram: how do I pass in '(.fooBar)?

17:29 bbloom: i don't think it's a special case or unpredictable behavior. it just requires a smarter compiler

17:30 technomancy: callen: my favourite part is how people complaining about square brackets seem to be oblivious to the fact that they sound *just* like the "too many parens lol" crowd

17:30 qed: llasram: (so it's callable later)

17:30 llasram: bbloom, technomancy: As continue to think about it, do you know if anyone has proposed #.method as reader syntax for auto-memfn'ing? Inside my head at least it seems really convenient

17:30 technomancy: llasram: could you experiment with it in user space using data_readers or whatever?

17:31 llasram: Oh! Yes

17:31 bbloom: llasram: it would require the compiler to use either reflection (slow) or to perform inlining & then would either need to A) fallback to reflection or B) error out for dynamic function use

17:31 llasram: bbloom: Oh, I was totes envisioning reflection

17:31 Maybe some invoke-dynamic love in the future

17:32 bbloom: *shrug* i think making it harder to use reflection is a good thing

17:32 callen: technomancy: that's largely why I don't complain, the syntax doesn't bother me. That having been said, there's something pleasantly and quietly conversational about Lisp.

17:32 bbloom: technomancy: the thing about the "extra" syntax in clojure is that scheme etc *already has special syntax for lists*. In fact, scheme has a binary infix operator for creating pairs & the parens are shorthand for that

17:33 llasram: qed: You'd write a macro which too the bare symbol names for the methods: (defmethodfns SomeType isFooBar isBazQuux)

17:33 bbloom: technomancy: in theory, the pair dot operator is a concrete constructor & you could have polymorphic implementations of lists

17:33 llasram: s,which too,which took,

17:33 bbloom: technomancy: extending that idea to maps & other data types is a NO BRAINER

17:33 (now that i've used with clojure)

17:33 llasram: bbloom: I mostly agree with you, but think making it easier to use Clojure is a good thing :-)

17:33 callen: bbloom: Lispers didn't like the dot either.

17:33 just fyi

17:34 bbloom: callen: but the dot is actually the opposite problem. it's going from something abstract (list notation) to something concrete (pair notation)

17:34 technomancy: bbloom: from what I can tell other lisps don't bother with maps

17:34 bbloom: technomancy: which blows my mind

17:34 callen: it's not really complicated

17:34 most maps as they are used in most languages don't need to be actual maps

17:35 just associative pairs

17:35 bbloom: sure, we've got association lists too, but we call them PAM

17:35 choosing to use a concrete representation is a bad plan

17:35 callen: I know there's a concrete impl that is similar

17:35 there's a *reason* I use Clojure after all

17:35 I'm just making the point that Lispers were accustomed to picking and choosing the bits they wanted.

17:36 whether that be an assoc list or hash-table

17:36 technomancy: I get the feeling in scheme hash-tables are only used if you don't know the possible keys up-front.

17:36 bbloom: you can think of clojure's syntax as being a pre-macro compiler pass which evaluates forms corresponding to abstract data types

17:36 technomancy: which is why it doesn't bother people that they don't have usable literal syntax, as far as I can tell

17:37 callen: I'm not saying I mind Clojure syntax, I'm saying it took me time to stop being grumpy about it and I understand why others might be.

17:37 technomancy: thanks again for limit-break :P

17:37 technomancy: but stuff like update-in seems more onerous with hash-tables or alists or whatever

17:38 bbloom: update-in is glorious.

17:38 technomancy: callen: cool; at least someone is using it

17:38 bbloom: it's like 90% of lenses without a phd :-)

17:38 callen: technomancy: Ritz is too baroque, I have to use it.

17:38 tomjack: 90%??

17:38 lazybot: tomjack: What are you, crazy? Of course not!

17:39 callen: bbloom: you've insulted tomjack's hobbies.

17:39 bbloom: tomjack: ok 20%, whatever. go give me the other 80% as simply as keywords & vectors work w/ update-in :-)

17:41 tomjack: it's one point in a whole space, I'd say 0% :)

17:41 bbloom: nope, i'm going with the 80/20 rule :-P

17:41 callen: but for the rest of us, it's 80%

17:43 new rule, if I can't grep around for what the JIRA ticket is referencing and nobody answers my question on the JIRA task, it's not getting done.

17:43 technomancy: what's wrong with the old rule of "if it's on JIRA, it's probably not getting done"?

17:43 bbloom: so the nice thing about update-in & friends is that you get something lens-like without having to A) create an entirely separate set of objects or B) use data with quoting/unquoting wrapper objects

17:43 tomjack: bbloom: yeah 80/20 probably applies :)

17:47 callen: technomancy: I like to try.

17:47 I also like a clean JIRA panel so that I can do other things.

17:53 leif-p: Hey everybody. Can anyone point me to some design docs for core.async and/or suggestions of non-trivial applications to hack on to learn it? tbaldridge, I'm looking in your direction.

17:56 tbaldridge: leif-p: there's this, but like you said, it's trivial https://github.com/clojure/core.async/blob/master/examples/walkthrough.clj

17:56 besides that and the golang talks/tutorials, I don't really have much else.

17:57 leif-p: tbaldridge: what about design docs? Did you work off of any papers / implementations when composing that gnarly macro / compiler?

17:58 bhauman: leif-p: I'm assuming your aware of this https://github.com/swannodette/async-tests

17:58 tbaldridge: leif-p: I got the ideas from https://github.com/scala/async#how-it-works , but the actual code/design is my own work.

17:59 leif-p: it's one of those things where C#, and Scala both do similar transforms, but from what I've been able to find, haven't really published how they do it.

18:00 There's also this, that might help a bit: http://hueypetersen.com/posts/2013/08/02/the-state-machines-of-core-async/

18:00 bbloom: tbaldridge: scala's approach uses shift/reset (delimited continuations) & is documented here:

18:01 http://infoscience.epfl.ch/record/149136/files/icfp113-rompf.pdf

18:02 tbaldridge: bbloom: you're thinking of Scala's CPS transform, the code I linked to is from the async implementation, https://github.com/scala/async#comparison-with-cps-plugin

18:02 bhauman: leif-p: there's also this: examples from Hoare's paper rewritten in core.async https://github.com/nodename/async-plgd

18:02 tbaldridge: Leave it to scala to implement two ways of doing the same thing

18:03 leif-p: tbaldridge: Yeah, I saw async-tests, and it seemed UI-focused, but it *will* probably help me get my head around the programming model. The docs you and bbloom just sent will probably be enough for me to muddle through (and keep me busy for a long while). Thanks, all!

18:03 bbloom: ah, my misunderstanding. thanks for the correction

18:05 oh interesting, they are doing local state machines too. cool

18:17 devn: http://www.flipscript.com/data/AMBICBar_K1W1M0G1b2363X1,1-207,50;G0c4c95X1,51-207,100;G231b61X1,101-207,150;G512c16X1,151-207,200;S2G917341X1,201-207,250;S2Gff96ffX1,251-207,300;S2Gfbefa3X1,301-207,350;S2Ge2e2e2X1,351-207,400;G323232X1,401-207,450.pngx?dv=0&cq=99&tn=0&rg=1&gs=2&ff=3&w1=clojure&w2=&ff=3&amp;pk=369970934

18:17 yeesh, sorry about that URL

18:33 mikerod: n00b question probably, but how do I change the value of a Var without re'defing it? I am getting this "IllegalStateException Can't change/establish root binding of: my-var with set clojure.lang.Var.set (Var.java:233)" using set! . I know that I can use alter-var-root, but is that my only option?

18:33 I'm not wanting to just dynamically rebind it either.

18:34 Raynes: Don't.

18:34 bbloom: yeah, what Raynes said

18:34 but also, you can use alter-root-var with constantly

18:34 Raynes: But don't.

18:34 bbloom: yeah, what Raynes said again

18:35 mikerod: Raynes: bbloom this is only for a testing scenario with code I'm not keeping around

18:35 Raynes: If you really need state, use an atom or something.

18:35 mikerod: more of an interactive thing

18:35 bbloom: mikerod: in that case, use with-redefs

18:35 mikerod: bbloom: Ok, so what is a use-case of set! and var-set? Just out of curiousity.

18:35 curiosity*

18:36 bbloom: mikerod: dyhnamic bindings are mutable

18:36 like if you need a thread local atom or something, you can just var-set inside a binding form

18:36 but it's pretty rare / often a bad plan

18:39 mikerod: bbloom: Ok, that makes sense.

18:39 bbloom: https://groups.google.com/forum/#!topic/clojure/PCKzXweeDeY

18:39 that post actually explains it pretty clearly

18:39 the reason mutable vars is OK is b/c they have dynamic extent, so they can't escape via a closure

18:39 which means you can't break thread safety

18:40 mikerod: That makes sense. Thanks for the link, reading through it.

18:41 So *warn-on-reflection* is an example of a dynamic Var. I see it is defined in RT. It seems I can do a (set! *warn-on-reflectoin* true) from within the REPL.

18:41 bbloom: and if you use bound-fn, you're essentially cloning (part of) the execution environment, so mutating a dynamic var in your extent won't affect bound-fns which can modify the dynamic vars in their isolated dynamic extents

18:43 mikerod: looks like RT.java calls push-thread-bindings on startup

18:43 basically, warn-on-reflection is bound in the dynamic extent of main

18:44 oh no, more accurately:

18:44 there is a try/push/finally/pop in there, which is akin to the binding macro

18:44 and it wraps the file loading process

18:44 mikerod: Ah, that makes sense.

18:45 That's what initially threw me off that I couldn't def a Var similarly and use set! on it. Makes sense now that it fits into being bound in the dynamic extent.

18:46 bbloom: unfortunately (or thankfully?), clojure's module loading logic is not pluggable in anyway, otherwise you could do the same trick. in theory, you could imagine registering a hook that gets passed the loading thunk & you could wrap a binder around that

18:46 but clojure doesn't offer such a feature

18:51 mikerod: Yeah, I guess that doesn't upset me too much really since I haven't really ran into wanting to do this much before anyways.

18:52 bbloom: use with-redefs :-)

18:53 mikerod: Now that I look again, I see this same binding mechanism is used in clojure.main. Thanks for helping me understand that. Enlightening. with-redefs is workable.

18:57 cromney: anybody run into an issue where InetAddress/getByName works, but InetAddress/getAllByName fails to resolve the same hostname?

19:00 akurilin: Quick style question: is it reasonable to place argument checks into a do block, assuming they either do nothing or throw an exception?

19:00 bbloom: mikerod: this also reminds me of something i was wondering a few months ago: I wonder if performance is the *only* reason why lazy-seq & friends don't use bound-fn. i suspect so

19:01 hiredman: I imagine the other reason is binding conveyance is just gross

19:01 bbloom: hiredman: you think that even for thunks?

19:02 hiredman: yes, which doesn't mean I don't do it, because it is useful

19:02 but it can cause all kinds of edge cases which I wish just weren't there

19:03 bbloom: which edge cases are you thinking about in particular?

19:03 hiredman: for example what does the clojure predicate thread-bound? mean?

19:03 bbloom: i spend a lot of time thinking about dynamic extent, effects, and context. since they seem to be kinda the unsolved "hard" problems in the functional world

19:03 hiredman: (I think it is thread-bound?)

19:04 bbloom: (doc thread-bound?)

19:04 clojurebot: "([& vars]); Returns true if all of the vars provided as arguments have thread-local bindings. Implies that set!'ing the provided vars will succeed. Returns true if no vars are provided."

19:04 cromney: akurilin: have you looked at pre-conditions?

19:04 bbloom: hm, i've never felt the need for such a predicate, i couldn't imagine what i need it for....

19:04 what have you used it for?

19:04 hiredman: does it mean that the var was bound in this thread, or that the binding was conveyed, and if I have a macro that tries to establish a thread local binding, and only one binding

19:06 doing binding conveyance in lazy-seqs brings even more edges

19:07 bbloom: so part of the issue is the "full" capture of bindings

19:07 instead of a delimited capture

19:07 hiredman: miles of edges

19:07 bbloom: like if i have a *current-thread-id* and it's set to 5

19:07 then i bound-fn, and then run that on another thread, i'm fucked

19:07 hiredman: assuredly

19:08 bbloom: there is a need for delimiters: http://okmij.org/ftp/Computation/dynamic-binding.html#DDBinding

19:08 hiredman: which, future and agent sends now helpfully do for you :(

19:08 bbloom: bound-fn is akin to a full, non-composable continuation :-/

19:09 hiredman: so, you know, leave it out, if I need to capture the dynamic environment I can capture it lexically and rebuild it myself

19:10 bbloom: yeah, ok, you've prompted me to think about it and caused me to sell myself what you're offering :-)

19:10 hiredman: but rich maybe has some idea for building a conditional system using them or something

19:10 he mentioned something like that at his conj keynote where he said binding conveyance was going to happen

19:12 bbloom: seems like core.async greatly diminishes the pressure to do something like that

19:12 b/c you can establish dynamic bindings in "forked" sub processes

19:12 and then you just parameterize both of them with a channel

19:12 the same channel, i mean

19:13 if java & javascript had fast, restartable exceptions, it might be a different story

19:13 noonian: what is a good place to point people at who are interested in learning Clojure but don't have much (or any) background in cs and/or programming?

19:15 hiredman: noonian: the best place to start is with some problem you want to try and solve

19:15 bbloom: hiredman: on a related note. i wish there were explicit dynamic parameters, and implicit static parameters. right now, we've got 2 diagonal corners of that 2x2 grid & the other 2 corners are lonely

19:15 actually, hm. i guess passing around atoms cover the explicit dynamic parameters thing, to some extent

19:16 noonian: hiredman: thanks, but I would like a good starting resource to point someone at when the other options they are considering are learning python or ruby and the like from somewhere like code academy or udacity

19:18 cromney: noonian: O'Reilly has some great videos that Neal Ford and Stu Halloway recorded called Clojure Inside Out

19:18 not free, but worth the investment imho

19:19 noonian: codeschool has some free Clojure vids iirc

19:19 hiredman: noonian: let them go there, the closest thing to those kind of classes are maybe the clojure training stuff the relevance guys do, but that is sort of few and far between

19:19 technomancy: bbloom: doesn't closing over something count as an implicit lexical parameter?

19:19 noonian: thanks guys

19:20 hiredman: once they have experience with other stuff, clojure should be very attractive to them and you won't be able to stop them picking it up

19:21 mikerod: bbloom: Interesting topic. This is the first I've looked into bound-fn. This gave me some things to add to the reading list.

19:21 bbloom: technomancy: i guess so, but it seems kinda rigid compared to what scala & haskell can do w/ implicit arguments

19:21 noonian: yeah, I'm just trying to present Clojure as an alternative because I doubt they are aware of it at all

19:22 bbloom: technomancy: although, those rely on a type system, i guess you could imagine an untyped variant of them. not sure what it would look like tho

19:22 technomancy: bbloom: "implicit" is uncomfortably close to "magic" in my experience

19:22 but I haven't used haskell or scala

19:22 bbloom: i can't change the literature, but i'd s/implicit/contextual/

19:22 callen: I have, I like it.

19:23 bbloom: oh, so interestingly, it seems haskell's implicit parameters are type checked, but resolved by NAME not by type

19:23 callen: technomancy: imagine refinements but not retarded. Like that.

19:23 bbloom: scala's implicit parameters are resolved by type, which seems dumb to me

19:23 callen: er, implicit arguments, not Scala implicits, sorry.

19:23 bbloom: http://www.haskell.org/haskellwiki/Implicit_parameters

19:23 callen: I misunderstood

19:25 bbloom: technomancy: compare to the approach here: http://www.scala-lang.org/old/node/114

19:26 bound-fn pushes/pops bindings on top of the dynamic bindings, which involves a linear scan of the bindings

19:26 in theory you could just *set* without supplementing the implicit bindings map

19:27 i'm not sure how either scala or haskell handle implicits with respect to closures tho

19:28 also, it seems common to want to transfer some subset of dynamic vars to implicit ones. there is this temptation to not pass *vars* but it makes sense to leave the dynamic extent world when you ultimately call a function that wants that argument from the lexical extent of the caller

19:29 callen: bbloom: closures themselves can have implicit arguments in Scala

19:29 https://issues.scala-lang.org/browse/SI-1492

19:30 bbloom: gotcha. i take issue with the dispatch by type, however

19:31 callen: there's a lot to take issue with in Scala, it's not a language for people whose dicks get raw at freckles on a pretty girl's face.

19:31 most people are just happy to have a non-trivial type system.

19:31 bbloom: i have no idea what that means, but i'm quite certain it's inappropriate in here

19:31 callen: bbloom: whining about relatively unimportant flaws.

19:33 cromney: ..

19:57 callen: cromney: are you not entertained?

20:00 TimMc: callen: Gonna have to agree with bbloom here.

20:09 callen: TimMc: I would too, if I were you.

20:11 llasram: wow

20:12 travisrodman: hello clojurians... i have a java compilation issue

20:12 i am building in maven, using a java class that has a static initializer

20:13 and when the clojure code is compiled, it seems to be executing the initialization of the class

20:13 instead of just compiling the code

20:13 technomancy: travisrodman: clojure code can't be compiled without being run

20:13 travisrodman: it works fine building in lein, and i am using the theoryinpractise plugin in maven for the build

20:14 hmm

20:14 llasram: travisrodman: Importing a class in Clojure forces the class to be loaded, which will run any static initializers on the class

20:15 travisrodman: that is unfortunate... is there any way to work around this without modifying the original java code?

20:15 technomancy: most likely lein wasn't doing any compilation at all

20:15 travisrodman: you could resolve the class at runtime. it's pretty awkward though.

20:15 and slow

20:15 travisrodman: thanks for the immediate feedback btw...

20:15 technomancy: or just don't AOT the clojure code

20:16 llasram: travisrodman: Not that I'm aware of. In code I control I've just been pushing things I want deffered into static inner classes

20:16 deferred even

20:16 No, I was right the first time -- just have erc-spelling-mode off somehow

20:17 travisrodman: unfortunately, the clojure code is primarily providing a dsl for the java, so the clients are looking to compile as part of the maven build

20:18 @technomancy: what would the class resolution at run-time look like... i can google that if the answer is too involved.

20:18 llasram: travisrodman: I'm not entirely following. Can you provide more details?

20:18 technomancy: I guess it's basically just reflection

20:19 travisrodman: @technomancy: right... see, I am using gen-class to output interfaces that can be utilized by the java in the larger system, so the AOT is somewhat necesary, I believe

20:19 @technomancy: in that case, how would you not compile the code, or would it be deferred in some manner i am not aware of if the clj's were just included in the jar

20:20 llasram: travisrodman: Oh! Instead, you can write Java stub classes which load Clojure namespaces and invoke functions via the Clojure Java APIs

20:20 travisrodman: @llasram: what can I clarify for you?

20:20 llasram: I believe your last statement clarified sufficient

20:20 sufficiently even

20:21 Oh, and FYI, in IRC you generally just refer to someone's handle directly. No need for an `@` prefix

20:21 travisrodman: ah, thanks

20:21 llasram: travisrodman: Here's an example of the style I've adopted lately: https://github.com/damballa/abracad/blob/master/src/java/abracad/avro/ClojureDatumReader.java

20:22 technomancy: yeah, you could bridge the gen-class->regular-clojure with runtime require and write your regular clojure using the class normally

20:22 travisrodman: technomancy: okay, i will look into that

20:23 llasram: thanks. i will look that over, but i am in the unfortunate position of not being able to bend the java to my will, but i am sure it will be worth looking at none-the-less

20:24 thanks, very much, for the feedback

20:24 llasram: travisrodman: Oh, sure, but you can add new Java. The philosophy is that you write Java to interface with Java, write Clojure to actually implement the program logic

20:26 travisrodman: out of the interest in understanding, why, during the maven build, would the code behave as though initialized, as opposed to just compiling, as you would with any other java? is it because it needs to run through the clojure compiler, and that is causing the instantiation?

20:27 llasram: in a sense, that is what the clojure is doing, i am using proxy to generate classes-on-the-fly so an entirely distinct group of users can augment functionality, without java or the original code

20:28 it is just that the some of the calls rely on classes in the java to support the dsl, and this is where this issue is coming in.

20:28 thanks for the code sample though... always expanding my understanding... I appreciate it

20:30 llasram: travisrodman: In Clojure compiling are less distinct than Java. You're essentially running some code, and just saving off the classes which are being dynamically generated. The running-of-code which loads namespaces loads any classes which are `:import`ed, which runs their static initializers

20:30 s,compiling,compiling and running,

20:30 travisrodman: llasram: that is very intersting... so in reality, instead of wrapping from the clojure perspective, you are consuming from the java side... very nice.

20:31 llasram: got it, in a sense, how the macros are expanding and replacing themselves with their executed values, until it finally settles on the final bytecode?

20:31 llasram: am i understanding that correctly? that was a bit of a statement that turned into a question.

20:32 llasram: Well, macros don't really enter into the picture, except in that macro-expansion is a step in code compilation. More to the point is that in Clojure, the compilation unit is the top-level form

20:32 And compilation/run time are only distinguished per top-level form

20:33 So once you've executed the `ns` form when loading a file

20:33 technomancy: which is really *so* much simpler than the alternative

20:33 llasram: Everything needs to be set up for anything which follows -- e.g., including code which depends on classes having been loaded

20:33 technomancy: if you look at the crazy backflips racket has to do to have a separate non-runtime compile phase... whew.

20:34 llasram: I really should look at Racket more...

20:34 travisrodman: I need to idle for a bit, but best of luck!

20:34 travisrodman: np... thanks for the info

20:36 technomancy: thanks for the tip on that i will check it out. i am sure the solutions you are presenting are cleaner, more straightforward, and in the end, better, it is good to know the alternative

20:53 Guest9805: Hi, everyone. I'm having trouble understanding a few methods in Clojure relating to Java interop. I saw a solution to a 4Clojure problem that used the (.get) method from Java, and I can't seem to find for the life of me what that function does or where it comes from. Mind you, I'm not a Java programmer, so it's been extra difficult.

20:58 Anyone?

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

21:01 hyPiRion: Guest9805: I wouldn't worry too much. It's most likely done on a vector or a map, in which case it is equivalent with a normal get

21:03 Guest9805: Ah, okay. Just tried both in the REPL, and they seem to work the same way. I guess that solution wasn't very idiomatic.

21:03 hyPiRion: yeah, sounds a bit strange

21:08 mthvedt: is there a way to make compojure not automagically wrap your return values in certain routes

21:18 xeqi: mthvedt: you could return a ring response yourself

21:19 mthvedt: xeqi: i want to return a map that's handled by ring middleware

21:28 xeqi: mthvedt: and what is compojure doing to the map?

21:29 sticking it in :body ?

21:29 mthvedt: xeqi: compojure routes add :headers, :response, and an empty :body to any APersistentMap

21:29 xeqi: ah, yeah https://github.com/weavejester/compojure/blob/master/src/compojure/response.clj#L23

21:32 mthvedt: i have middleware that turns maps into JSON responses, which compojure is interfering with, so that's annoying

21:51 jonh: bnls

21:52 coventry: Where would I find documentation for standard Server-Sent-Events code? (The pedestal tutorial is referring to it on the Making the Service wiki page.)

22:14 Oh, it's a javascript concept. I was looking for it in a clojure context.

22:24 egghead: coventry: it's something a server does that js can pay attention to

22:25 coventry: https://developer.mozilla.org/en-US/docs/Server-sent_events

22:47 coventry: egghead: thanks.

22:48 muhoo: mthvedt: there's a ring-json-middleware, IIRC

22:48 mthvedt: muhoo: stackoverflow suggests compojure breaks that middleware also

22:51 muhoo: i dunno. i'm doing a project rght now that retrns json for api endpionts, have not had any problems.

22:52 doign it manually, i..e (fn [req] {:status 200 :body (json/ncode (do-stuff req)))})

22:53 or rather (GET "/foo" req {:status 200 :body (jon/encode (do-stuff req))})

22:53 egghead: i'm doing some fun edn over websockets

23:14 llasram: Huh. This is interesting. A *data-readers* tagged literal constructor can return arbitrary forms, which are then treated as what has been just read by the reader. If the function returns forms which represent code and the forms are being compiled, the tagged literal can inject arbitrary code to be compiled

23:15 Maybe this intentional. It seems consistent. But I found it surprising at first

23:20 xeqi: llasram: or the data reader could just eval the string itself

23:40 Apage43: here's my json-response https://github.com/couchbaselabs/mortimer/blob/master/src/mortimer/web.clj#L26-L30

23:41 which i copy around because the existing middleware I've run across uses data.json, and I prefer cheshire

Logging service provided by n01se.net