#clojure log - Oct 27 2012

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

1:16 muhoo: wasn't the nyc the first ever clojure group?

1:16 i.e. didn't rhickey launch clojure to the nyc lisp group?

1:16 i thought he lived in nyc

1:23 amalloy: he's presented at the nyc meetup a number of times

1:25 eg cljs was announced there, and i think he gave a reducers talk not long after releasing them

1:27 ambrosebs: Now accepting contributions to Typed Clojure (Clojure CA only). Lots of small easy jobs I can give. https://github.com/frenchy64/typed-clojure

1:44 Sgeo: ambrosebs, I assume you use some macro-expander. I trust it's not clojure.walk/macroexpand-all?

1:45 ambrosebs: Sgeo: https://github.com/frenchy64/typed-clojure

1:45 whoops!

1:46 https://github.com/frenchy64/analyze rather

1:46 It's an AST :)

1:48 tomoj: wow

1:48 nice work

1:49 ambrosebs: next best thing to Clojure-in-Clojure!

1:49 clojure 1.5.0-beta1 only atm.

1:49 Sgeo: ,(do (require '[clojure.walk :as walk]) (walk/macroexpand-all '(quote (let [a 1] a))))

1:49 clojurebot: (quote (let* [a 1] a))

1:50 Sgeo: Just a demo of how utterly bad clojure.walk/macroexpand-all is

1:50 ambrosebs: Sgeo: good thing the clojure compiler knows how. ;)

1:51 g2g!

1:51 Sgeo: Bye

1:51 * Sgeo appears to be a bit single-minded...

1:52 Sgeo: I should learn how to praise and not just criticise

1:52 clojurebot: Cool story bro.

1:52 Sgeo: (Not that I have criticism about ambrosebs's work, because I don't)

1:57 andyfingerhut: Does anyone know how to modify a Clojure modular contrib module's pom.xml file (e.g. for data.xml) so that I can pass additional command line args to the java commands invoked to compile the code? Or is there a way to do it from the mvn command line?

2:46 brainproxy: trying to switch over to ritz-swank from swank-clojure but having some problems...

2:47 i've got a clean lein 2 project, and with the lein-ritz in my profile, I can fire up `lein ritz 4005` for example

2:47 and then I can use slime-connect to connect to it

2:47 from w/in emacs that is

2:47 but... I get a warning about slime and swank having different versions, *and* after choosing to continue past the warning, I never actually get a repl

2:48 i just get a notice the connection was made

3:37 muhoo: new i7 in the hizzy. now i can clojure it up with impunity.

3:59 S11001001: andyfingerhut: for scalar datatypes, there's usually a direct mapping between the XML options for each plugin and -D options you can give to maven

4:01 andyfingerhut: I assume the javac options are in string settings, so those should suit

4:25 scottj: brainproxy: well ritz does use a different version of slime than swank-clojure

4:43 brainproxy: scottj: yes, but I had swank-clojure uninstalled and was installed the version of slime rec'd by the ritz-swank readme

4:43 anyway, for now just using nREPL and nrepl.el

5:12 wingy: im making a SDK for an HTTP API .. i have some options for how to deal with the HTTP API endpoint: 1. pass the url to the functions 2. hardcode it in the functions 3. have it in the SDK's config.clj file

5:15 option 3 seems to be a flexible one .. what is the best practice for this?

5:27 andrewmcveigh: wingy: you can throw out #2 - that's crazy, #1 might get tedious, passing a URL to every function call.

5:27 wingy: so 3?

5:28 andrewmcveigh: well, out of those 3 options, I'd pick #3.

5:28 wingy: andrewmcveigh: are there more optons?

5:28 options

5:29 andrewmcveigh: i just thought about FP .. shouldn't all data be passed as params?

5:29 andrewmcveigh: many java/.net sdks use a singleton to store the current "binding" - not suggesting that this is a good option.

5:30 wingy: what do you do with other configurable options?

5:30 wingy: yeah

5:30 i guess i put them in config.clj

5:30 btw .. i think having a *service-url* is good

5:31 much better than a config.clj

5:31 andrewmcveigh: how do you set *service-url*?

5:32 wingy: andrewmcveigh: does this mean that i have to wrap them inside (binding [*service-url*] (make-request))

5:32 you said binding and i thought about dynamic binding

5:32 andrewmcveigh: I quoted "binding", because it has nothing to do with clojure's binding...

5:32 wingy: but that is a good idea?

5:33 kinda like *out*

5:33 andrewmcveigh: Personally, I don't think singletons are a good idea in clojure, but I'm no expert.

5:35 wingy: I think if you're doing something like (binding [*service-url* (:service-url (read-config))] (make-request)) - that's alright.

5:36 wingy: andrewmcveigh: is there a way to set *service-url* once so all SDK fns dont have to be wrapped?

5:37 andrewmcveigh: ,(doc alter-var-root)

5:37 &(doc alter-var-root)

5:37 lazybot: java.lang.SecurityException: You tripped the alarm! alter-var-root is bad!

5:38 Bronsa: ,alter-var-root

5:38 &alter-var-root

5:38 lazybot: java.lang.SecurityException: You tripped the alarm! alter-var-root is bad!

5:38 Bronsa: woah :(

5:38 andrewmcveigh: wingy: or you could use an atom/ref to hold it.

5:39 wingy: that's mutable territory though.

5:40 wingy: ,(def *service-url* (atom "http://service.com/api"))

5:40 i'll try with it

5:41 not mutable, but switchable right?

5:41 the current state changes .. but the values don't

5:42 andrewmcveigh: if state changes... is that not mutation?

5:45 wingy: is it?

5:45 ok mutation in the identifier

5:46 correct me if i am wrong

5:47 andrewmcveigh: from http://clojure.org/atoms "Atoms provide a way to manage shared, synchronous, independent state. "

5:48 so if you (reset! atom1 5), you've changed it's state.

5:49 it's just been managed by clojure.

8:56 wunki: I keep getting "method not found" for trying to call the static `of` method here: http://thumbnailator.googlecode.com/hg/javadoc/index.html

8:56 trying to call it with `(Thumbnails/of ...)`

9:06 keugaerg: ,(+ 2 3)

9:07 ret

9:08 jonasac: hi, kinda new to clojure trying to get the examples repo form programming clojure2nd edition to work

9:08 did lein deps and it installed a bunch of stuff to .m2 folder

9:08 but when i run lein repl i cant import the example code like the book says

9:08 being told examples is not in the classpath

9:09 rod_: what's the command you're using to import the example code into the repl jonasac?

9:09 jonasac: (require 'examples.introduction)

9:10 rodnaph: and the file is "src/examples/introduction.clj"

9:10 jonasac: yep

9:10 rodnaph: with (ns examples.introdution) as the namespace?

9:10 and u start the repl from the folder that contains "src"

9:11 jonasac: yes and yes

9:11 rodnaph: what's the exact error? can you paste an example session to refheap.com (from cd'ing to the folder, ls'ing the contents and starting the repl)

9:12 jonasac: lein self-install helped

9:12 i installed clojure via homebrew

9:12 but it works now

9:13 rodnaph: oh right (sorry if i got the wrong end of the stick, just joined channel)

9:14 jonasac: no, thanks for the help, just joined myself

9:15 been mising lisp ever since SICP at uni

9:16 rodnaph: clojure is my first lisp, real eye opener though.

12:06 erwagasore: I am doing clojure koans and I am stuck, need help: (= 25(__ ((fn[n] (* n n))))

12:06 what should I put in __ place?

12:08 antares_: erwagasore: do you have a link to the example?

12:10 erwagasore: antares_ line 24 test https://github.com/functional-koans/clojure-koans/blob/master/src/koans/06_functions.clj

12:11 antares_: erwagasore: ok, that example makes sense

12:12 erwagasore: antares_ maybe I need to understand what|how higher-order functions works after all.

12:13 antares_: http://clojure-doc.org/articles/language/functions.html#higher_order_functions

12:14 ,((fn [f] (f 5)) (fn [n] (* n n)))

12:15 $ ((fn [f] (f 5)) (fn [n] (* n n)))

12:15 ~((fn [f] (f 5)) (fn [n] (* n n)))

12:15 lazybot: help

12:15 lazybot: You're going to need to tell me what you want help with.

12:16 antares_: erwagasore: well, here is your answer: a function that takes another funtion (the squaring one) and calls it with an argument of 5

12:30 erwagasore: antares_ amazing thanks now I understand

12:39 dnolen: bbloom: thx for the core.logic patch

13:22 tomoj: sitting here wondering whether I need to create a new datomic db or whether the changes I made to the schema are compatible with what's already there. I hadn't committed to git yet. I should have, but still, using git history for that would suck. a few lines of code lets me say "ok, pretend I committed this schema tx, then clojure.data/diff that with my current schema" :D

13:30 TimMc: lazybot: help me with my homework

13:30 lazybot: Topic: "me" doesn't exist!

13:31 TimMc: Oh good, it isn't self-aware yet.

13:38 hyPiRion: lazybot: What is the purpose of life?

13:46 Well, it isn't even aware.

13:46 At least not fully aware.

13:46 AdmiralBumbleBee: maybe it is aware, but it's too lazy to make it fully apparent

13:47 tomoj: it seems aware of some of what I type

13:47 AdmiralBumbleBee: it's aware of all of it, too lazy to respond to all of it

13:48 maybe someone needs to kick it with a doall

13:58 bbloom: dnolen: my pleasure. thanks for posting that OZ link on the mailing list the other day. i found it really helpful for understanding how core logic works

14:00 dnolen: bbloom: Oz is pretty neat, the Prolog-like bits of core.logic are quite different from Oz, but I basically want to steal the Oz FD feature set wholesale

14:01 bbloom: dnolen: yup, i'm most interested in optimization

14:02 as in minimization, not perf

14:02 although perf is also important :-)

14:03 dnolen: are there any examples of solver systems that include both a finite domain solver and some other category of solver? for example a linear programming solver that operates on floating point values?

14:03 dnolen: bbloom: as am I. core.logic needs a distribute functionality - it's pretty easy add.

14:04 bbloom: core.logic already has multiple solvers, CLP(Tree) & CLP(FD), it's also a goal for both to be present in the same program.

14:05 bbloom: and I would like to see CLP(R), floating point ops

14:05 bbloom: dnolen: same program == same top-level "run" form? i.e. the same constraint system?

14:06 dnolen: seems like this CLP(X) form turns up some results in the literature. is there a survey of this terminology and the various types of solvers?

14:06 dnolen: bbloom: different constraint solvers in the same run yes

14:06 bbloom: dnolen: i may be interested in contributing a Simplex solver for linear inequalities -- I want to use it for UI layout

14:07 dnolen: bbloom: I'm not aware of a survey, but lots of various papers of course

14:07 bbloom: that would be sweet

14:09 bbloom: dnolen: meanwhile, i have my CLJS CPS transform in pretty good shape… there's one small patch to analyze fn methods that would help me get it to a released state :-)

14:10 dnolen: bbloom: cool, yes I saw that will take closer look soon. related, your patch did break top level lets, do you have any thoughts about fixing that?

14:10 bbloom: top level lets? hmmm

14:10 let me look

14:11 dnolen: bbloom: http://dev.clojure.org/jira/browse/CLJS-401

14:11 bbloom: top level lets just drop JS vars at the top level, gensym protected overwriting, that's no longer the case

14:11 bbloom: dnolen: d'oh! makes sense

14:11 gtrak: errr... someone must know the answer to this. I've been trying to create a clojure.test fixture that looks for exceptions in an agent, and I can't find a proper way to report the error. Throwing exceptions kills the main test-runner thread, using clojure.test/do-report seems to die on 'lein test', though it works on swank: https://gist.github.com/27cac036ef633a2b5cdd

14:11 bbloom: ill see what i can come up with

14:12 dnolen: bbloom: thx much

14:12 bbloom: I mention a possible fix, but I haven't had a chance to try it out. Might totally kill perf since if you have enough nested functions GClosure won't optimize.

14:13 gtrak: the current approach: https://gist.github.com/562db53028a9a9a0218c

14:16 bbloom: dnolen: i know GClosure can optimize away top level self invocations … those (function() { … })(); forms

14:16 maybe we should do that for every top-level?

14:18 dnolen: bbloom: hmm, I'd prefer a patch that only did for top-level lets.

14:19 bbloom: dnolen: sure. it may be generally value to include "is top level" in the AST somehow

14:19 although, i guess you can infer that....

14:20 dnolen: bbloom: yeah I thinking you could tell this from env right, if so perhaps this is a simple fix.

14:22 bbloom: well env is statement, expression, return

14:22 there isn't really top-level, since that is the same as statement

14:23 gtrak: I think it's because I'm not having proper bindings... grr.....

14:25 bbloom: dnolen: yeah, it's not sufficient to do only top level lets

14:25 consider:

14:25 (do 1 (let [y 2] (js/alert y)) 3)

14:25 that exhibits the same issue

14:28 dnolen: bbloom: do doesn't introduce bindings so I'm not really concerned about that

14:29 bbloom: dnolen: no, the output of that is:

14:29 var y = 2; alert(y);

14:29 dnolen: bbloom: oh right

14:29 bbloom: still happens

14:29 :-/

14:29 dnolen: i think i can just change compile-file to wrap each top-level & it will be all good

14:30 dnolen: bbloom: sure give it a shot.

14:36 bbloom: dnolen: hmm interesting… compiler.clj and closure.clj both have a compile-file method… but it seems like the one in compiler.clj is unused

14:37 dnolen: bbloom: it used, closure.clj line 356 calls compile-file in compiler.clj

14:37 bbloom: also line 398

14:37 comp/compile-file

14:38 bbloom: ah comp/compile-file yes.. but the later case is a reference to line 349

14:42 dnolen: ok, well this seems to work. let me cleanup & test a bunch of stuff & then i'll submit a patch

14:46 dnolen: bbloom: excellent

14:47 wingy: what is the equivalent of setTimeout in clojure?

14:47 bbloom: dnolen: eh, never mind. doesn't play nice with def & especially with advanced optimizations

14:47 wingy: (with-timeout)

14:47 or hmm

14:48 dnolen: bbloom: darn. in what way is problematic w/ def?

14:49 wingy: ScheduledThreadExecutor I think

14:49 bbloom: well so you get globals by omitting the "var" keyword

14:50 wingy: dnolen: can i use Thread/sleep

14:54 dnolen: wingy: that's not really equivalent to setTimeout as that will block execution of your program unlike in JS

14:54 amalloy: of his current thread, anyway

14:54 bbloom: dnolen: ok, so the issue is that in advanced mode, top-levels of the form x.y.z = w will get intelligently converted to namespace export things, where x and x.y will be initialized to {}

14:55 dnolen: but if you wrap the func around that, then it won't do it

14:55 dnolen: bbloom: right

14:55 bbloom: dnolen: not sure if there's a way around that

14:57 goog.provide?

14:57 dnolen: bbloom: doubt it. I think we need to reify the notion of the top level in the AST, perhap a :scope field in env, it gets set to top

14:57 bbloom: let will should modify the scope to be something other than :top

14:57 bbloom: dnolen: that won't help because you can have a def inside a let

14:58 (let [x 1] (def y x))

14:58 if you wrap that in (function(){…})();

14:58 then def breaks

15:00 dnolen: bbloom: I think the approach on the ticket is ok minus the hacky dynamic var bit. just gensym top level lets in the compiler.

15:00 bbloom: on the existing patch on the ticket.

15:03 bbloom: there lots of annoying edge cases to consider here. "the top level is hopeless" to quote Felleisen

15:04 bbloom: dnolen: goog.provide is what we want :-P

15:06 dnolen: bbloom: ah so you're suggesting wrapping everything, and emitting a provide for each top level? :)

15:06 bbloom: yes

15:06 trying that now

15:06 dnolen: bbloom: k

15:07 bbloom: dnolen: should also help with some dependency analysis stuff, since now goog closure will have publish export info for each def

15:08 wingy: is jetty creating a thread for each request?

15:09 dnolen: wingy: yes

15:09 bbloom: surely it has a thread pool…

15:11 dnolen: bbloom: right, wingy: using a thread per request

15:13 wingy: cool

15:14 soon you will see a good comparison between js/node.js/express and clojure/ring/compojure/hiccup

15:15 Sgeo: express?

15:15 tomoj: great

15:16 I plan to argue that to my team shortly

15:16 Sgeo: :/ is that the thing my gf is raving about?

15:16 tomoj: except .. hiccup

15:17 bbloom: debugging advanced output is a pita.

15:18 dnolen: bbloom: yep

15:27 brainproxy: express is pretty nice, there's also restify and strata

15:28 tomoj: I haven't thought about it enough yet, but I expect the choice connect made about middleware causes trouble for express

15:28 brainproxy: they all work similarly but have different goals, if you will, and so offer different bells and whistles

15:29 tomoj: express 3.0 may have completely solved that trouble, but I doubt it

15:29 * callen twitches

15:29 brainproxy: tomoj: can you elaborate?

15:29 in any case, I now vastly prefer ring/compojure/liberator

15:30 tomoj: a middleware in connect is like (fn [req res next])

15:30 brainproxy: haven't had occasion yet to experiment w/ aleph

15:30 tomoj: where ring has (fn [next] (fn [req] res))

15:30 I suspect this causes composability issues

15:31 brainproxy: well, passing the res object along is pretty important given the async nature of things

15:31 tomoj: not to mention that you side-effect a response out instead of returning one

15:31 that's just because they didn't solve the async problem

15:32 brainproxy: well given that js doesn't have threads, then unless you're going to introduce a control flow mechanism along with the router

15:32 then you're stuck w/ the "async problem"

15:32 although some folks don't see it as a "problem" per se

15:32 it's just the nature of the beast

15:33 tomoj: yeah, it could make sense to build something better over connect

15:33 brainproxy: i think the approach strata takes is to embrace the streams concept very deeply

15:33 tomoj: if you can return a response stream, great

15:33 brainproxy: so as you pass control through the handlers, you're working with streams

15:34 tomoj: or do you just write to the response stream they give you?

15:35 brainproxy: tomoj: not sure, haven't really gotten into it, just know some folks using it, heard them talk about it, have looked at the website from time to time

15:35 http://stratajs.org/manual

15:38 AntelopeSalad: what is the standard way to run jetty in production mode if any?

15:38 tomoj: looks nicer

15:38 middleware has the right shape

15:40 it looks weird because you create a Response out of nowhere and then response.send(callback), but that's pretty much sugar for passing the response to the callback, which is the low-level async equivalent of returning it

15:43 http://news.ycombinator.com/item?id=3021564 "leaky abstraction" looks like a fully general counterargument

15:43 ""leaky abstraction" looks like a fully general counterargument" looks like a fully general counterargument :(

15:46 brainproxy: it's been over a year since that HN piece, and the project is still actively dev'd

15:47 so I guess something's working out for the users of it

15:51 bbloom: dnolen: sorry, had to step out

15:51 dnolen: unfortunately, i don't think my idea works either… b/c then you have conflicts between top level vars and namespace names.

15:51 dnolen: consider namespace foo with symbol bar and namespace foo.bar with symbol baz

15:53 this further solidifies my belief that, while cute, POJsO make poor namespaces

15:56 hmm i guess the top-level vs namespace conflict already exists....

15:59 dnolen: bbloom: yeah I don't see how that's a problem.

16:04 AntelopeSalad: is there a ring setting i need to enable so it handles etags properly?

16:06 tomoj: is there an entity binding syntax hidden in datomic already? something like :where [?p {:person/name ?name :person/age ?age}]

16:06 I mean besides :where [?p :person/name ?name] [?p :person/age ?age] ofc

16:08 sritchie: does anyone here have experience with monadic parsing in clojure?

16:08 I'm writing a parser using clojure.algo.monads and working off of the numerous recursive descent parser blog posts out there,

16:09 but I haven't seen any project that pulls all of those combinators together into their own project

16:10 gensymv: hello, is there a particularly good way of defining pointfree functions in clojure?

16:10 defining them with def seems a whole lot slower then explicitly naming the arguments

16:14 see exhibit a https://www.refheap.com/paste/6185

16:15 callen: gensymv: well you know what they say about points-free programming...

16:15 gensymv: it's pointless.

16:16 gensymv: callen, that's really helpful.

16:16 callen: I was going for punny.

16:16 jasonjckn: sritchie: I don't, but have you tried asking for help within your near social network?

16:16 sritchie: jasonjckn: :)

16:16 dnolen: gensymv: there's very little support for that style in Clojure

16:16 sritchie: jasonjckn: I'll use your clarsec

16:16 jasonjckn: Sweet

16:16 sritchie: can we get it updated to use clojure.algo.monads?

16:17 bbloom: gensymv: that's function call overhead of less than 0.0003 msecs

16:17 jasonjckn: i wrote my own monad

16:17 bbloom: seems pretty reasonable to me

16:17 Sgeo: sritchie, clojure.algo.monads's maybe-m monad breaks the monad laws

16:17 callen: sritchie: you should write a parser for C++

16:17 gensymv: bbloom, i see it as approx 30 times slower ^^

16:18 sritchie: C++ to clojure, that'd be a nice weekend

16:18 callen: sritchie: my deeper point is that I'd be impressed if you simply wrote a passable C++ parser in using parser combinators.

16:18 'simply'

16:18 sritchie: jasonjckn: writing your own parser monad's cool, but defining it using clojure.algo.monads lets you use the existing domonad, m-lift, etc

16:18 Sgeo: interesting

16:19 bbloom: gensymv: seems like premature optimization to me....

16:19 dnolen: gensymv: you should look at the implementation of partial - it relies on rest args and apply, you're just not going to get super great perf out of partial.

16:19 jasonjckn: sritchie: I have those 2 ops

16:19 sritchie: take it or leave it :)

16:19 sritchie: an exercise to the reader is to port it yourself

16:20 gensymv: dnolen, so you essentially say that currying is not what clojure is built for.

16:20 bbloom: gensymv: no. you can do currying

16:20 sritchie: callen: I'm working on a far more junior-level project

16:20 bbloom: gensymv: what dnolen is saying is that partial supports variadic functions

16:20 sritchie: parsing the thrift IDL

16:20 gensymv: ah

16:20 callen: sritchie: parsing C++ is demi-junior.

16:21 bbloom: gensymv: which haskell doesn't…. which makes optimizing currying and partial application easier

16:21 gensymv: so the two functions aren't semantically equivalent

16:21 wingy: we have a guy here wanting to switch back to node.js because he says jetty can't cache correctly

16:21 bbloom: gensymv: right. you can implement curry without var args & you'll get better perf

16:21 wingy: is this correct?

16:21 callen: wingy: that doesn't make any sense at all.

16:21 wingy: cache what?

16:21 gensymv: bbloom, thanks that is helpful.

16:22 jasonjckn: sritchie: one disadvantage algo.monad is you need to wrap everything in with-monad, makes it hard to C-xC-e your parsers with interactive development

16:22 sritchie: sure, that's true

16:22 callen: wingy: jetty is a web server.

16:22 Sgeo: sritchie, note protocol monads, a different implementation. Although it uses do as a macro name, which kind of sucks

16:22 dnolen: wingy: it's so sad that some of the thing they say about Node.js users is so true - http://www.youtube.com/watch?v=bzkRVzciAZg

16:22 jasonjckn: sritchie: also, because i'm using multi methods, you can derive monad's from other monads, although I haven't used that feature, limited value afaik.

16:22 marcellu`: how do I call extend-type for a type from a different namespace?

16:22 callen: dnolen: <3

16:23 sritchie: Sgeo: interesting, thanks for the tip

16:23 Sgeo: yw

16:23 sritchie: https://github.com/jduey/protocol-monads

16:23 callen: sritchie: now go write a C++ parser

16:23 sritchie: will do, sensei

16:23 wingy: dnolen: im on your side

16:29 antares_: marcellu`: the same way but you make it qualified, e.g. otherns/MyType and you may have to import it in some cases

16:30 tomoj: hmm, `:where [(fn-returning-integer ?x) [?int ...]]` gives "Don't know how to create ISeq from: java.lang.Integer" as expected, but `:where [(fn-returning-integer ?x) ?int]` gives "ArrayIndexOutOfBoundsException 2"

16:30 oh

16:30 whoops

16:32 antares_: wingy: Jetty is an embeddable Web server. It almost certainly does not do caching automatically (not of its business) but you can set etags/last-modified in your app just like with anything else.

16:32 jasonjckn: sritchie: honestly, as cool as monadic parsers are, recursive decent parsers will never surpass LR/LL parsers afaik in performance

16:32 sritchie: https://github.com/cgrand/parsley

16:32 sritchie: yeah, that lib is really cool

16:32 jasonjckn: sritchie: never used it, but that's probably the best clojure parser

16:32 wingy: AntelopeSalad: ^

16:32 sritchie: for anything beyond thrift / learning experience, I'd go there

16:32 maybe I'll do it in both

16:35 wingy: http://www.youtube.com/watch?v=bzkRVzciAZg good one :)

16:39 jasonjckn: sritchie: so you're trying to build a parser with algo.monads and you're not sure how?

16:39 sritchie: no, I'm doing fine

16:40 it works, it's great,

16:40 just wanted to know if someone else had built up these combinators in a lib I should use

16:40 jasonjckn: sritchie: never seen a lib that used algo.monads

16:40 most people rolled their own

16:40 sritchie: midje

16:40 jasonjckn: for parsing?

16:40 sritchie: no

16:41 jasonjckn: ok I meant to add that qualifier

16:41 sritchie: I think you did parsing before algo.monads

16:41 yeah

16:41 jasonjckn: yes

16:41 exactly

16:44 mklappstuhl: I'm having trouble with namespaces here: https://github.com/mklappstuhl/computational-investing.clj

16:44 trying to load the core presents me this:

16:44 user=> (require 'mklappstuhl.stock-utils.core)

16:44 WARNING: extend already refers to: #'clojure.core/extend in namespace: mklappstuhl.stock-utils.util, being replaced by: #'clj-time.core/extend

16:44 CompilerException java.lang.IllegalArgumentException: Parameter declaration quote should be a vector, compiling:(mklappstuhl/stock_utils/metrics.clj:1)

16:45 jasonjckn: mklappstuhl: you don't nest defn's inside ns

16:45 mklappstuhl: (ns foo) (defn …) etc

16:47 mklappstuhl: jasonjckn, I which file am I doing this?

16:47 jasonjckn: sritchie: some languages need to be tokenized in order to parse successfully.

16:47 antares_: mklappstuhl: metrics.clj, see the exception?

16:47 jasonjckn: https://github.com/mklappstuhl/computational-investing.clj/blob/master/src/mklappstuhl/stock_utils/metrics.clj

16:48 mklappstuhl: jasonjckn, wtf o.O I have this file open in vim and it looks completely different ?!

16:48 jasonjckn: mklappstuhl: save it

16:49 mklappstuhl: jasonjckn, I just closed and reopened it and its still the correct version

16:49 jasonjckn: well push your changes to git

16:49 master

16:50 mklappstuhl: jasonjckn, sure. I just did git add . and git commit 2 minutes ago...?! kind of confusing, haha

16:51 jasonjckn, pushed

16:51 jasonjckn: ok it's updated

16:52 that file looks fine

16:52 try recompiling

16:52 mklappstuhl: jasonjckn, seems to work now...

16:53 jasonjckn, sorry this probably made a wierd impression :D

16:54 jasonjckn: sounds like you had some old cached files, not sure

16:56 sritchie: consider if ( true ) {}; if = 2; if your parser is (<|> assignment-statement-pfn if-statement) then you'll incorrectly accept 'if' as a variable name

16:57 sritchie: unless your assignment-statement-pfn is defined to exclude the parsing of keywords. which if expressed through combinator parsers would be super slow

16:58 the correct way to handle that is to tokenize first (with maximal munch)

16:59 …so the assignment-statement-pfn will try to accept the token "symbol" and it'll encounter the token "if"

16:59 and fail

17:00 Roxxi: Hey, if I want to make a new record that is sortable, is there a Protocol or interface I can have it implement so that (clojure.core/compare rec1 rec2) automatically works?

17:00 I suppose analgous to Comparable?

17:01 Or is it just java.lang.Comparable o.O

17:04 Looks like it is..

17:05 bbloom: dnolen: see http://dev.clojure.org/jira/browse/CLJS-401?focusedCommentId=29830

17:06 dnolen: bbloom: so we don't need goog.provide?

17:07 bbloom: dnolen: nope! the issue was that i needed to not wrap the top level ns form

17:07 dnolen: bbloom: excellent! this looks good!

17:08 bbloom: thx much

17:08 bbloom: dnolen: my pleasure! but while you're thanking me, you can also merge the patch at http://dev.clojure.org/jira/browse/CLJS-408 :-)

17:09 Kneferilis: hello

17:10 dnolen: bbloom: will do will apply these in a little bit

17:11 bbloom: dnolen: one last one: a small cleanup i made while working on the top-levels patch: https://gist.github.com/3966254

17:11 dnolen: if you want that too :-)

17:12 dnolen: bbloom: sure ticket+patch I'll apply it as well.

17:12 bbloom: *sigh* so much overhead :-/ but ok

17:13 can i sneak it in on the other ticket? heh

17:13 dnolen: bbloom: heh, nope

17:15 bbloom: http://dev.clojure.org/jira/browse/CLJS-409

17:15 dnolen: bbloom: thx

17:28 mklappstuhl: I have this little project here and I'd like to run simulations on collections of stock symbols... I have a rough draft of how I could structure this in simulate.clj but I'm pretty sure there are other more clojure-esque ways to do this

17:29 so I'd love to have some input :) 'm just starting with clojure btw

17:30 gfredericks: is simulate.clj a library? or just a file of yours?

17:30 mklappstuhl: https://github.com/mklappstuhl/computational-investing.clj

17:31 gfredericks, forgot the link somehow ... ^

17:31 gfredericks: righto

17:32 I'm more prone to comment on low-level things first

17:32 like your call to hash-map could be a map literal

17:32 e.g., (hash-map name trades) => {name trades}

17:33 hard to say much more about this without knowing how you're intending to use it

17:33 mklappstuhl: gfredericks, I know about the hash map thing... I just feel like its more readable

17:34 I'm happy about any input like this one too though

17:34 gfredericks: I almost never see clojure code like that; but it's a minor point, and even more minor if this code is just for yourself

17:36 mklappstuhl: gfredericks, I want to run simulations on historical data with fictional transactions at the beginning

17:36 kind of like:

17:36 10MM of AAPL shares

17:36 5MM of IBM shares

17:37 with a date when the stocks were bought and an end date for the simulation

17:37 gfredericks, good to know about the hash-map convention

17:40 gfredericks: so you're simulating the value of a fictional portfolio given actual historical prices?

17:40 mklappstuhl: gfredericks, yes

18:00 dnolen: bbloom: patches applied

18:01 bbloom: dnolen: cool, thx

18:47 Raynes: Hrm

18:47 thearthur_: strange Incanter problem,

18:47 Raynes: I wonder how targeting nodejs and writing libraries in it works.

18:47 thearthur_: yesterday incnater charts stopped displaying (i suspect they are displaying off screen)

18:48 gensymv: hello, in ubuntu 12.10 i installed the package clojure-contrib, but somehow cannot "use" it from clojure. i tried locating the libraries but had no lock with it. can anybody help me pls?

18:48 *luck

18:52 bbloom: Raynes: you mean for cljs? it should work reasonably well, but won't really play super nice with the module system

18:53 Raynes: bbloom: I'm talking about how one would write a library in cljs they could distribute with npm and use in other nodejs-targeting cljs apps.

18:53 The whole namespace system for regular clojurescript makes no sense to me at all though.

18:53 So I don't really even understand how you'd do that there either.

18:54 bbloom: Raynes: well clojurescript piggybacks on Google Closure's module system. if you wanted to target node's module system, you could just refer to js/window.exports to bypass the symbol munging in both cljs and google closure

18:54 Raynes: That easy, eh?

18:54 ;)

18:55 bbloom: Raynes: heh, yeah it is. just use bin/cljsc in the clojurescript source tree. when used with advanced compilations, it will compile your entire app to a single .js file

18:56 Raynes: How does that help with library distribution?

18:56 bbloom: Raynes: in that file, you can do something like (set! js/window.exports somesym somesym) to export functions to the node ecosystem

18:56 just check in the .js output :-)

18:56 i think package.json can run your build script pre-publish too

18:57 Raynes: That's kinda convoluted though, isn't it? And it also includes all of Clojure as well.

18:57 bbloom: in theory, it should only include the bits of clojure that you depend on

18:57 but we've got still some shortcomings for dead code removal

18:57 you just make sure the functions that you expose take plain javascript objects

18:57 dnolen: Raynes: someone could easily provide CLJS w/ simple optimizations + :static-fns as an npm module, and

18:57 bbloom: similar to how you'd stick a C interface on a C++ library

18:58 js/window.exports -> js/module.exports

18:58 dnolen: Raynes: then CLJS compiler would need a option to compile w/o core so you can provide your own libs w/ core as a npm dep

18:58 bbloom: sorry, been a while since i did some node.js

18:58 dnolen: bbloom: dead code elimination matters a whole lot less for node.js

18:59 bbloom: dnolen: i know, but Raynes said "it also includes all of Clojure as well" :-)

18:59 dnolen: bbloom: non-issue in my mind.

18:59 bbloom: agreed

18:59 dnolen: 20,000 lines of JS is nothing to v8

19:00 Raynes: But wouldn't there be issues with duplicated functions, or clashes, or something?

19:00 dnolen: given that tools like emscripten generation hundreds of thousands of lines of JS and the modern engines handle it well

19:00 who cares on the server

19:00 Raynes: It wasn't size I was worried about.

19:00 bbloom: Raynes: node's module system should protect you there

19:00 dnolen: Raynes: I mentioned ^ that you would need a way to compile your own lib w/o core.

19:01 Raynes: we could add that feature to the compiler.

19:01 Raynes: But didn't you just say that it didn't matter? :(

19:01 * Raynes gets confoosed sometimes.

19:01 dnolen: Raynes: I said dead code elimination didn't matter.

19:01 different thing altogether

19:01 advanced compilation is not relevant for server side JS

19:01 bbloom: heh, i think it doesn't matter… doesn't node's module system prevent globals without explicit references to `global`?

19:02 dnolen: i mention using advanced compilation so that you can get a single js output w/o needing to muck with the stitching logic of that top level output js file… but there may be some other easy way to get a build step to concatenate those

19:02 dnolen: bbloom: yeah but I'd still be concerned w/ confusing v8 and deoptimization if multiple versions of cljs.core are getting loaded.

19:03 bbloom: dnolen: ah, good point. i forget that we muck w/ prototypes

19:06 dnolen: in general, there is some ugliness in the compiler around the module system

19:06 it might be nice to provide something like a namespace compilation protocol, to support pluggable module systems

19:06 would be nice to decouple us from the closure compiler, even tho it's super useful now

19:07 dnolen: bbloom: yes Node.js case in point

19:08 bbloom: dnolen: yup :-) also worth discussing at some point is the namespaces atom

19:08 dnolen: bbloom: though the Node.js module model simply sucks in a massive way.

19:08 the whole wrapping all libs in function making everything opaque is total shit.

19:08 bbloom: dnolen: yeah, common.js is the simplest possible realization of the brain dead objects == maps == namespaces world view

19:09 dnolen: it's particularly great for thwarting interactive development. you want to "use" some symbol, so you do `var foo = pkg.foo` and then you later want to redefine pkg.foo, but that doesn't impact `var foo`!

19:10 argh.

19:10 python suffers from a similar issue

19:10 dnolen: bbloom: so it makes adopting the Node.js model in the compiler less compelling, but it means sharing libs w/ Node.js and vice versa kinda lame as it is today.

19:11 bbloom: either way, protocol-izing the module system would help us better understand the requirements

19:11 dnolen: though to be honest I just don't see Node.js folks using CLJS libs, the style of programming is just incredibly different.

19:12 bbloom: tangentially related: i'd also like to purify that ana/namespaces atom ;)

19:12 dnolen: bbloom: sure what do you have in mind?

19:12 bbloom: oh heh, i already said that…

19:12 didn't mean to repeat myself :-)

19:13 some kind of "compilation unit" AST node

19:13 dnolen: bbloom: ? in ana/namespaces ?

19:13 bbloom: no, instead of that atom

19:14 dnolen: bbloom: what for?

19:14 bbloom: i haven't fully thought it out, but i ran into some minor annoyances while debugging my CPS transform b/c that atom was stateful

19:15 or at least b/c it is bound at the top-level, rather than within the scope of a compilation unit

19:15 dnolen: bbloom: this will require considerable thought since the utility of having it around for reflection is quite significant

19:16 bbloom: dnolen: yeah, it's just a gut reaction to "ugh, that thing annoys me".. i wonder if it could be made unbound and :dynamic, and then there could be a with-world type macro

19:17 dnolen: definitely needs more thought. I'm just gonna let the thought bake for a while

19:17 dnolen: bbloom: it's worth investigating, would allow lein-cljsbuild to get parallel builds back too.

19:17 bbloom: mmm parallel builds :-)

19:18 oh, that brings up one other thought

19:19 AST transformations seem to be inherently discrete. by that i mean you have to complete transform A before you can do transform B. if you wanted parallelize, you could only really do it by compilation unit

19:19 i wonder if top-levels could be processed lazily… such that you could have A run on form 0, then while A is running on form 1, B is running on form 0

19:19 dnolen: does that make any sense?

19:20 (assuming you have two cores)

19:20 i think i answered my own question: yes :-P

19:21 except that the top level ana/namespaces prevents it...

19:21 dnolen: bbloom: heh lein-cljsbuild parallel-build was just a way to build multiple version of the script at the same time

19:21 bbloom: you're thinking about something more ambitious

19:22 bbloom: having the compiler be able to compile different files in parallel would probably be the source of the most win w/o adding too much complexity.

19:22 frawr: Having some unexcpected behavior with lein run here. When I change something in the code and do lein run again, i get weird errors. I have to call lein clean first everytime.

19:22 bbloom: dnolen: yup

19:23 amalloy: frawr: aot compilation makes things complicated. don't do it unless you absolutely have to

19:23 frawr: So clear the aot list?

19:23 And when would I have to?

19:24 frozenlock: Is there a function like clojure.contrib.string/take available?

19:24 amalloy: mainly when you want to expose a named class to a java program, or if you need really complicated gen-class stuff

19:24 &(doc subs)

19:24 lazybot: ⇒ "([s start] [s start end]); Returns the substring of s beginning at start inclusive, and ending at end (defaults to length of string), exclusive."

19:24 frozenlock: Excellent, thanks!

19:25 amalloy: frawr: yes, clear :aot, and adjust your main entry -- :main ^:skip-aot myapp.main

19:27 frawr: thnx

19:28 the errors are normal ones now, thnx. speeds up the proccess a whole lot.

19:29 biscarch: How do I access a Java property? Equiv code in Java would be Environment.SANDBOX

19:30 bbloom: Environment/SANDBOX

19:30 biscarch: ::facepalm:: thanks

19:30 hyPiRion: ,(Integer/MAX_VALUE)

19:31 &(Integer/MAX_VALUE)

19:31 lazybot: ⇒ 2147483647

19:31 hyPiRion: &Integer/MAX_VALUE

19:31 lazybot: ⇒ 2147483647

19:33 bbloom: dnolen: so let me know how i can help with distributions stuff in core.logic. I'd really love to general purpose minimization technique for prototyping a bunch of ideas i have :-)

19:34 dnolen: i may ultimately need special purpose solvers, but general minimization would go a long way during the design phase

19:47 dnolen: bbloom: there's a key fn called map sum which tries each value of vars domain

19:48 bbloom: a bunch of strategies could be added there, including possibly a custom cost function which knows how vars are entailed and which order to try which values.

19:49 bbloom: currently it completely naive and just tries them in order and doesn't consider relationships between vars

19:49 gotta run

19:49 bbloom: k, i'll need to study it more. probably won't get to it for a while.

19:49 cya

20:05 callen: I still say Clojure needs a mascot like go.

20:05 Clojure...Clown Fish?

20:06 Iceland_jack: That sounds horrifying..

20:09 hyPiRion: http://www.flickr.com/photos/lndr/2648570113/

20:09 It's not the blue/green colour scheme though

20:15 wingy: is it possible to use something like (str) but strip all whitespace?

20:15 since i am using (str) in my code and the test and they are not the same since they contain different indentation whitespaces

20:16 due to their positioning in the source file

20:16 callen: hyPiRion: I'm sure that with some food dye, anything can be arranged.

20:16 wingy: but if i strip all whitespaces then they will be equal

20:19 Somelauw: ,(clojure.string.replace "white spaced" #"\s+" "")

20:19 &(clojure.string.replace "white spaced" #"\s+" "")

20:19 lazybot: java.lang.ClassNotFoundException: clojure.string.replace

20:19 Somelauw: &(clojure.string/replace "white spaced" #"\s+" "")

20:19 lazybot: ⇒ "whitespaced"

20:20 wingy: &(clojure.string/replace "white spaced yes <input \>" #"\s+" "")

20:20 lazybot: java.lang.RuntimeException: Unsupported escape character: \>

20:21 wingy: &(clojure.string/replace "<input \><a>some link</a>" #"\s+" "")

20:21 lazybot: java.lang.RuntimeException: Unsupported escape character: \>

20:22 wingy: doesn't seem to be a good idea .. ill just stick with having the multi line string starting without indentation

20:30 i start to love xml :/

20:32 callen: wingy: YOU TAKE THAT BACK RIGHT NOW

20:34 wingy: *swallowing*

20:36 hyPiRion: callen: colorizing the image is easier ;)

20:45 Somelauw: wingy: xml stands for everything that is wrong with this world :P

20:45 wingy: xml is more powerful than json!

20:46 Somelauw: More powerful? Both can represent the same datastructures?

20:46 wingy: and we are quite used to it through html

20:46 html as json would be messy

20:48 Somelauw: Maybe I should make a tool that can convert back and forth between s-expressions and html.

20:49 xml is the reason i hate maven and ant

20:50 I think cmake is much more readable than ant

21:12 akhudek: Tried eclipse for a day, and though I like CC, eclipse is just so slow compared to IntelliJ.

21:21 hyPiRion: Oh, sweet

21:22 DST is off here in Norway, so I can hack for one more hour

21:22 turned off, or what you call it.

21:27 akhudek: hyPiRion: isn't it mostly dark in Norway this time of year?

21:30 hyPiRion: akhudek: It's "okay" right now - the sun shines from 8 am to 5 pm.

21:31 akhudek: oh that's not too bad

21:32 hyPiRion: It's worse in December, then the sun rises 10 am, and it's pitch black around 2:30 pm

21:33 akhudek: wow! I visited Bergen once, but it was fortunately during the summer. Very nice then!

21:34 hyPiRion: heh :) Norway is a good place to live/be at summer, I think

21:35 Though I suppose people living at hotter places may disagree

21:36 akhudek: I'm in Canada, but in the southern parts. In december it's dark by 5, but that's the worst that it gets

21:39 hyPiRion: It's not easy, livin' in these countries far north.

21:46 biscarch: has anyone used the java Braintree library? or can point me to a recent example for using third party java libs?

21:49 akhudek: biscarch: http://clojure-doc.org/articles/language/interop.html

21:50 biscarch: akhudek: haven't seen that yet. Thanks.

21:50 akhudek: biscarch: the only other trick is getting the library jars into the classpath

21:51 if it's in maven, you can just get lein to pull them in like [groupid/artifactid "version"]

21:52 biscarch: akhudek: I set it up a :java-source-path in leiningen. I 'll check to see if the lib is in maven though

21:57 akhudek: biscarch: as long as the jars in get into the classpath you'll be fine. I just find setting things up via lein deps to be the most convenient

22:06 Sgeo: Someone should write a Leiningen installer for Windows

22:07 xeqi: Sgeo: do you mean something beyond the lein.bat ?

22:08 Sgeo: xeqi, putting wget or curl on the path, and putting lein.bat somewhere on the path

22:10 AntelopeSalad: would it be a good idea to use require instead of use 99% of the time?

22:10 xeqi: AntelopeSalad: yes

22:10 Sgeo: ah, right. I forgot about that prereq

22:10 akhudek: AntelopeSalad: also, when using use, it's good practise to use :only

22:11 helps to know what the specific dependencies are

22:11 AntelopeSalad: akhudek: yeah, that seemed to be a common trend in some examples i've seen

22:11 Sgeo: xeqi, also, I didn't use emacs-starter-kit much, but I think there's more to getting emacs set up for Clojure than it. Clojure-mode too, I think?

22:12 AntelopeSalad: i need to get used to searching for different terms

22:12 every time i google for ring, it assumes i'm going to type ring worms

22:13 akhudek: prefixing with clojure always seems to work for me

22:13 xeqi: clojure-mode, clojure-test-mode, nrepl-mode, paredit-mode

22:13 AntelopeSalad: yeah or put github in there somewhere, i find myself looking at the api docs pretty often

22:14 for some reason i can't get wrap-file-info working properly though

22:15 it never reports back what the docs say

22:17 akhudek: AntelopeSalad: if you are using it in conjunction with wrap-file, make sure that wrap-file comes first

22:18 AntelopeSalad: yep, i am

22:18 i followed this to a T https://github.com/ring-clojure/ring/wiki/Static-Resources

22:19 the api docs say it should give me the content-type and last-modified but it doesn't seem to

22:19 akhudek: I take it you've restarted your jetty server since adding it?

22:19 AntelopeSalad: yep, it just omits reporting back those header fields every time

22:20 i'm not sure of the idiomatic way to handle responses yet (this is basically day #1 of coding with clojure for me)

22:20 i've been using ring responses with the default keynames, i figured the middleware would change the response as necessary

22:23 akhudek: I don't have any more guesses for you, but I've found it helpful to dump the actual responses or requests at various points to figure out what is going on.

22:23 you can use something like this: https://www.refheap.com/paste/6188

22:23 oops, I had a bug

22:24 it's fixed now

22:24 AntelopeSalad: i wouldn't have to manually setup the keyname for content-type and last-modified right?

22:24 akhudek: no

22:24 AntelopeSalad: example: https://github.com/ring-clojure/ring/wiki/Creating-responses

22:25 i've been using the -output- directly as my response

22:25 except i didn't include the headers

22:25 akhudek: if you look at the code https://github.com/mmcgrana/ring/blob/master/ring-core/src/ring/middleware/file_info.clj

22:26 AntelopeSalad: the only thing i really changed from the guide is i transformed those uses into requires

22:26 akhudek: the only way I can see that it wouldn't add the right keys is if the body is not a File object

22:26 AntelopeSalad: but i guess it would have crashed if i did something wrong

22:26 all the other middleware works following the same require pattern

22:26 Sgeo: Is the Joy of Clojure not available on Nook?

22:26 AntelopeSalad: hmm, the body in all cases so far has been either a string or a function to a hiccup function

22:27 akhudek: are the strings path names or something?

22:27 AntelopeSalad: nope, just random output

22:28 i built up some examples without using templating, and then added templating after

22:28 :body "foo" , etc. stuff like that

22:28 akhudek: Oh. Then I'm confused why you are using file-info

22:28 it's for augmenting file responses, not html responses

22:28 AntelopeSalad: that could do it haha

22:29 so far i've only been passing around hiccup functions to the response body

22:29 i wasn't sure how else to do it (could probably figure it out with google)

22:29 i had a layout clj file setup with a namespace, and then imported into my main app file, etc.

22:30 how would i let ring know to keep track of last-modified for non-file responses?

22:31 akhudek: what would the last-modified time of a generated file be?

22:31 or do you mean the last modified time of the template?

22:32 AntelopeSalad: i'm honestly not sure, i only bring this up because another language puts an etag in the header for all responses

22:32 and i was trying to get that to happen with ring too

22:32 this way it can return 200 or 304, etc.

22:33 akhudek: well, in general, for all languages, you can only return a last modified time for static content

22:33 AntelopeSalad: this was an etag in specific, not last-modified

22:33 akhudek: or effectively static content like a compiled template

22:33 AntelopeSalad: not sure of the value, it looked like a negative unix time maybe

22:33 i think it does compile templates for you

22:34 is there a way to tell ring or hiccup to compile/cach templates automatically?

22:34 *cache

22:35 akhudek: not that I know of

22:35 though that doesn't mean such a thing doesn't exist

22:35 I suppose you want some form have middleware that tracks if a response has changed since the last call

22:36 AntelopeSalad: so this would certainly lie on the shoulders of ring/ring's middleware not the template language?

22:36 Sgeo: "Purchase includes free PDF, ePub, and Kindle eBooks downloadable at manning.com."

22:36 How do I get those?

22:37 akhudek: AntelopeSalad: it could be handled by either, though probably doens't happen currently

22:38 AntelopeSalad: a quick search turns up http://akoestler.blogspot.ca/2011/11/selective-browser-caching-with-etags-in.html

22:38 then just change the etag every time you change your code

22:38 if you are doing hiccup style outputs

22:38 AntelopeSalad: checking

22:40 what's that crazy +global-etag+ syntax mean?

22:40 akhudek: nothing

22:40 AntelopeSalad: i know + is ok to have as a variable name, but does it have context?

22:40 akhudek: author just likes plus signs I think

22:41 Sgeo: In Common Lisp, it's stylistic to have constants named with + on each side, I think

22:41 akhudek: it's not idiomatic to signify globals that way though

22:41 AntelopeSalad: ah, he does mention his def is a constant (but should be changed later)

22:42 thanks btw, this article seems pretty good -- i wonder why this isn't default functionality in ring, or at least a highly offically unofficial third party middleware

22:43 akhudek: probably a combination of nobody looking into it enough to write something, and also that the problem isn't actually trivial to solve in a very generic way

22:43 I mean, that solution requires you manually version your app, and make sure you don't apply the tag to dynamic responses.

22:45 AntelopeSalad: it seems to be solved in other libs

22:46 i couldn't say if the solution is ideal/perfect but i haven't seen anyone complain yet

22:53 akhudek: AntelopeSalad: give me a bit and I will give a shot at a middleware

22:53 AntelopeSalad: if you know javascript i can point you to a very good lib which handles auto-etags

22:53 the code doesn't seem too hairy, might be able to get it even without js knowledge

22:57 seems to be a 3 step problem: 1) a fn to generate the etag, 2) a value to store whether or not the request is fresh or not, 3) a fn to set fresh's value and the etag as well as trim out irrelevant headers when it's stale (content-type+length)

22:58 callen: hyPiRion: I prefer food dye.

23:02 hyPiRion: callen: Well, each to their own, I suppose.

23:08 Sgeo: What function does ` use to namespace a symbol?

23:10 ,(let [foo 'bar] ``~foo)

23:10 ..

23:10 &(let [foo 'bar] ``~foo)

23:10 lazybot: ⇒ clojure.core/foo

23:10 Sgeo: &(let [foo 'bar] `~foo)

23:10 lazybot: ⇒ bar

23:13 ambrosebs: Sgeo: hard to tell exactly where this is done.

23:16 Sgeo: do you just want the semantics, or literally where the code is?

23:17 Sgeo: The semantics, although literally where the code is would be interesting

23:17 ambrosebs: Sgeo: clojure.lang.LispReader$SyntaxQuoteReader/syntaxQuote I think

23:17 in clojure/lang/LispReader.java

23:19 Sgeo: Why is that else way out there on L802?

23:19 ambrosebs: I think syntax quote just tries to resolve the symbol, and if it doesn't resolve to a var, just qualify it in the current namespace.

23:19 Sgeo: &`~@[1 2]

23:19 lazybot: java.lang.IllegalStateException: splice not in list

23:19 ambrosebs: Sgeo: Rich works in mysterious ways in Java :)

23:19 Sgeo: I assume it's Rich

23:20 I've never seen Java quite like the Clojure compiler.

23:20 But I don't read much Java.

23:20 arosequist: I'm trying to learn core.logic fds. (+fd x y 5) works for x + y = 5, but what if I want x - y = 5? Is there a way to negate a domain?

23:21 (that might be a really dumb question...brand new to core.logic in general)

23:21 hyPiRion: arosequist: x - y = 5 <==> x = 5 + y, ain't it?

23:21 I don't know if it works for +fd though.

23:21 (Not used core.logic, shoot me for that :( )

23:22 arosequist: hyPiRion: Ah, it works perfectly. Of course. Thanks.

23:26 akhudek: AntelopeSalad: you can try this https://www.refheap.com/paste/6189

23:27 there is probably a better way to implement it, but it seemed to do the right thing in light testing

23:27 AntelopeSalad: ok

23:27 i will experiment with it tomorrow, using it should be straight forward right?

23:27 just throw this into my app.clj file and then put it into the middleware stack?

23:27 akhudek: also expect a performance hit to the server, though I don't know how much. Computing hash values certainly takes time

23:28 yep

23:28 AntelopeSalad: just so i'm 100% clear on this for later

23:28 https://github.com/ring-clojure/ring/wiki/Static-Resources

23:29 all i would have to do is replace: wrap-file-info with wrap-etag , right?

23:29 akhudek: right

23:29 it computes the etag only on the body

23:29 so as long as the body is set

23:29 it should work

23:29 AntelopeSalad: i wonder how bad the performance hit would be

23:29 akhudek: no clue

23:30 AntelopeSalad: in the end it should save time i would think

23:30 akhudek: well, for the client, not for the servers cpu

23:30 xeqi: I would expect it to save bandwidth, not really cpu time

23:30 AntelopeSalad: if it doesn't have to recompile a template and serve it, that's a pretty big win

23:31 akhudek: responses will still be generated

23:31 it only saves bandwidth

23:31 AntelopeSalad: yeah but as a slimmed down 304 right?

23:31 akhudek: nope, full responses are generated using this

23:31 for static files you can do much better

23:32 AntelopeSalad: hmm

23:32 why couldn't we set the body to empty on 304?

23:32 akhudek: so for performance, you'd want to use this only on non-static but rarely changing responses

23:32 AntelopeSalad: then send an empty body

23:32 akhudek: I think it does work that way

23:32 so you do save bandwidth

23:33 and your site will appear faster to clients

23:33 AntelopeSalad: so it is working in the way that is sends an empty body on 304s?

23:34 or would that doing something to "res" and then just wiping the body before returning it?

23:34 *require doing

23:35 akhudek: when I tried it with curl, curl didn't download the body when setting the if-none-match

23:35 not sure if that is just curl doing that, or jetty doing it

23:35 AntelopeSalad: did you curl it with verbose mode?

23:35 akhudek: yup

23:36 AntelopeSalad: would it be a good idea to remove the content-type and length for 304s too?

23:36 akhudek: if you want, you can also modify the handler to additionally clear the :body

23:36 not, sure, I didn't read the specs that closely

23:36 also easy changes to make :)

23:36 AntelopeSalad: i ask because of this: https://github.com/visionmedia/express/blob/master/lib/response.js#L129

23:37 he strips out those 2 headers and clears the body on 204/304

23:39 we could probably use crc instead of hash too to eliminate some calculations?

23:40 akhudek: looks like ring does have etag support https://github.com/ring-clojure/ring/blob/master/ring-core/src/ring/middleware/not_modified.clj

23:40 oops, should have checked first

23:41 that still won't add etags to dynamic responses though

23:41 AntelopeSalad: but it had nothing to write the etag

23:41 yeah

23:42 your middleware handles both right?

23:42 it clearly writes an etag and sends a 304 when it needs to

23:43 akhudek: yes, but it might be better to use this https://www.refheap.com/paste/6190

23:43 and then not-modified on top

23:43 AntelopeSalad: on top as in, 1 function before this one in the middleware stack?

23:43 akhudek: Ideally you'd only use wrap-etag on non-static routes, since static files will have last-modified times.

23:44 not-modified must come after wrap-etag

23:44 AntelopeSalad: ok, might as well use that then for sure?

23:45 the smaller wrap-etag + built in last-modified

23:45 akhudek: right, use this version as it fixes a capitalization issue: https://www.refheap.com/paste/6191

23:46 AntelopeSalad: the built in one looks like it's doing so much more than your first version

23:46 akhudek: yeah, it checks last modified time too

23:46 AntelopeSalad: i guess that's necessary?

23:47 akhudek: no, but it's optimal for static resources

23:47 you don't really want to be computing hash values on big files like images for example

23:47 AntelopeSalad: so we would want last-modified to run on all requests

23:47 and wrap-etag on just non-static requests?

23:48 akhudek: right, you want file-info on static requests, and wrap-etag on other requests

23:48 AntelopeSalad: that will involve editing wrap-etag in some way to skip doing its thing?

23:49 akhudek: no, you can just group your dynamic routes and add wrap-etag only to that group

23:49 check out compojure's defroutes

23:49 AntelopeSalad: i'm not really sure to "fork" 2 middlewares based on a condition

23:49 *how to

23:50 hmm that seems weird

23:51 when i look at defroutes, i think it's to be used to associate a group of routes to a sub-route

23:51 like /user/foo , /user/bar

23:52 akhudek: it can group any handlers

23:52 AntelopeSalad: what happens if you have a bunch of dynamic routes with no pattern

23:52 akhudek: e.g. https://www.refheap.com/paste/6192

23:53 AntelopeSalad: like /foo and /bar might be dynamic but aren't related

23:53 akhudek: they are checked in order until the first non-nil response

23:53 AntelopeSalad: oh wow

23:53 akhudek: I think there are tutorials around for that too. I personally quite like compojure for url routing

23:53 AntelopeSalad: the way you have this is nothing like what the docs say

23:54 this seems like arbitrary grouping (a very good thing)

23:54 https://github.com/weavejester/compojure/wiki/Nesting-routes

23:54 how the heck are we supposed to know what you just did when we read that lol?

23:55 akhudek: that page is talking about the context macro

23:55 there are better docs and tutorials around for compojure though

23:55 if you dig

23:55 AntelopeSalad: yeah, that'll be tomorrow's project -- thanks for pointing me in the right direction

23:55 i think this is a very good start to have a reasonable solution

23:56 akhudek: your welcome, the clojure web libraries take a while to learn, but they are pretty great once you know them

23:56 AntelopeSalad: btw what's your opinion on using a crc lib instead of hashing to save some cpu time, or do you think it's not even relevant?

23:56 akhudek: crc is a form of hashing

23:57 AntelopeSalad: brief googling (stackoverflow) seems to say it's less cpu intensive

23:57 akhudek: there may be more performant hash routines than clojures built in function though

Logging service provided by n01se.net