#clojure logs

2011-04-26

00:00dnolenmec: you could reify instances of ISeq to override the undesirable behavior.
00:04dnolenmec: but I guess what you really want is custom seq behavior w/o losing the record benefits?
00:06mecdnolen: I thought you couldnt implement ISeq directly on a record, I swear before it was giving me errors, so my initial question is pointless
00:07chrissbxmec: well, how do I "go to the repl" when in slime? slime is opening the inspector at this point, no way to type anything
00:08mecchrissbx: hmm in mine it opens the inspector in a different buffer so I still have the repl open
00:09chrissbxyes -- aha I can still type in the repl window and it will evaluate even though it looks blocked
00:09mecchrissbx: yup, any locals in scope are available to play with
00:10chrissbxHm, shows {} as local-bindings while there certainly are at least 2 function arguments where I put the break
00:10chrissbxDoesn't surprise me as the backtrace in slime also shows no locals everywhere.
00:10chrissbxDo I need to build the code with some debugging info flags?
00:11chrissbxs/everywhere/anywhere/
00:11mecchrissbx: ((fn [a b] (swank.core/break)) 1 2) gives me {a 1, b 2} with local-bindings
00:13mecOk so (defrecord Foo [bar baz] clojure.lang.Seqable (seq [_] '(1 2 3))) gives me a duplicate method error
00:13chrissbxhm, same thing for me; but when I do the same in code in a file, it eats some or all variables
00:14chrissbxlike in (defn >>= [a b] (swank.core/break) ...) it shows {}
00:14chrissbxin (fn [state & cont] (swank.core/break), it shows cont but not state
00:14dnolenmec: yeah, you can't do that.
00:16mecdnolen: so I'd have to make it a type instead of record?
00:16chrissbxI guess it does some inlining and optimizes variables away.
00:16chrissbxCan I tell the compiler not to optimize?
00:24dnolenmec: I haven't found a good way to deal w/ that situation - in my case switching to deftype wasn't a big deal since I didn't need all the defrecord machinery anyway.
00:27dnolenmec: a bit frustrating, but records have a contract to be map-like. Redefining seq like that would break anyone else trying to use your record in the usual way.
00:27chrissbxAm I too dumb to find the compiler options documentation, or are there no compiler options?
00:28chrissbxAre there declarations I can put into the source files?
00:28tomojdnolen: whew, thanks
00:28mecdnolen: makes sense, I suppose deftype isnt so bad in my case anyway
00:28tomojI don't like "it works (but it's evil)" advice
00:28tomoj(I guess if it _really_ worked it wouldn't be evil)
00:29mecchrissbx: im not sure I've ever heard of any clojure compiler options
00:30dnolenchrissbx: optimizing variables way doesn't sound right to me.
00:31chrissbxwell how else would you explain my observation?
00:35dnolenchrissbx: don't know, I'd bring it up on the ML, there's been a lot of chatter/interest in CDT
01:10technomancyno, it's known that the compiler clears locals when they aren't being used
01:10technomancyit's called fine-grained locals-clearing, and it helps avoid head-holding in lazy seqs
01:10technomancyyou can only observe a local if you place the breakpoint between its introduction and its last use
01:11technomancysee under The Gory Details: http://georgejahad.com/clojure/swank-cdt.html
01:11technomancychrissbx: ^^
01:13mectechnomancy: thats pretty cool
01:14technomancymec: yeah, it usually doesn't get in the way
01:16brehautdoes slurp look in resources ?
01:21technomancybrehaut: (comp slurp clojure.java.io/resource)
01:21brehauttechnomancy: great, thanks
01:22technomancynp
02:41seancorfield__gosh darn, they added more 4clojure problems!
02:46amalloyseancorfield__: lucky that we added an rss feed too
02:46amalloyand registered 4clojure.org for poor misguided souls
02:49seancorfield__re: .org - excellent!
02:51seancorfield__i haven't checked if the RSS feed is fixed on rockmelt yet
02:52amalloyseancorfield__: it's not fixed on chrome, so probably not. i'm told that if you install google's official "make rss feeds work" plugin, it works
02:56seancorfield__'k... probably explains why RockMelt on the iPhone rejects the 4clojure.com/problems/rss link
03:03brehaut$findfn (fn [x] (= x 2)) [1 2 3 2 2] 3
03:03sexpbot[]
03:05amalloybrehaut: there are so many goals for which 3 would be the right answer there...are you looking for (comp count fiilter)?
03:05clojurebotcount arities is http://groups.google.com/group/clojure/msg/fb9930ba2a25d2dd
03:05brehautamalloy: yeah i am
03:06brehautamalloy: in particular i was looking for not manual
03:06amalloyi thought you might want ##([1 2 3 2 2] 2) ; 3
03:06sexpbot⟹ 3
03:07brehautaha
03:07brehauti wish :)
03:09markomanhmh. im doing (defentity Form) in database namespace and trying to include Form on other namespace, but compiler says: Unable to resolve classname: Form
03:11markomani tried with inc and require as db/Form but doesnt work. Why defentity symbols work only on same namespace?
03:12markomandefentity is from appengine-magic library
04:12thorwilmarkoman: i guess that's because defentity is a macro
04:13markomanso what you make with macro, you cant import to other namespaces?
04:13thorwilwait, that would affect defn, too
04:14markomani made a workaround by creating a function on database namespace and by calling it I can get defentity symbols
04:15markomanbut it feels weird why I can use symbols only inside namespace I define them
04:20thorwilmarkoman: if you do a macroexpand on a defentity call, you might see why. and maybe have to collect your jaw from the floor
04:21markomanheh, lets see
04:26markomanhmh, I think i cant use macroexpand
04:26markomansays: Can't take value of a macro
04:26raek(macroexpand-1 '(defentity ...))
04:29raekmarkoman: from what I can tell (haven't used appengine myself) (defentity Foo ...) results in a (defrecord Foo ...), but also a (defn foo ...)
04:29clgvThe new repl feels more comfortable but break the debug-repl macro I used that employs the clojure.main/repl. thats probably due to the server-repl approach I guess?
04:30markomanmacroexpand starts with (let* [] (deftype* Form user.Form
04:31raekthe generated type is a class, so you need to import it after you have required/used the namespace
04:31raekor you can use the generated constructor function
04:32thorwilor perhaps consider if you can keep all the datastore business in a single file. you could call it "models.clj" ... ;)
04:33markomanthats what I did so far. ut yeah, this explains, type is a class and needs import
04:33markomanbut i have another problem now, which makes no sense to me
04:34raek(ns the.dependant.namespace (:require the.db.namespace)) (the.db.namespace.Foo. ...)
04:34raekor
04:34raek(ns the.dependant.namespace (:require the.db.namespace) (:import the.db.namespace.Foo)) (Foo. ...)
04:34raeknote the trailing dot and the lack of a slash
04:34raek(this is java interop syntax)
04:35raek(ns the.dependant.namespace (:use [the.db.namespace :only [foo]])) (foo ...)
04:35markomanah
04:35raekif you use the constructor fn instead (which is an ordinary function)
04:35markomanI didnt know the dot marking, that would work too
04:36raekI have no idea if you are supposed to use the generated type directly or if you are supposed to use the generated function
04:37markomanbut now when I created constructor (entity-get :kw) it doenst work with (:use or (:require for some reason
04:37markomanmaybe constructor is not good term here, but just a function to get types
04:38raekwhat I mean by constructor is a fuction (foo ...) that is a wrapper for (Foo. ...) to simplify its usage
04:40markoman(:require [magicforms.database :as db]) and try to call it (db/entity-get :form) I get java.lang.IllegalArgumentException: Unable to resolve classname: (db/entity-get :form)
04:42markomanwhen I get into the namespace or just use or require it on repl user namespace it works. but not when I try to compile the file
04:42raeksounds like there's an error in something else than the use/require mechanism
04:43clgv$seen lpetite
04:43sexpbotI have never seen lpetite.
04:43clgv$seen lpetit
04:43sexpbotlpetit was last seen quitting 6 weeks and 5 days ago.
04:43clgv$seen cgrand
04:43sexpbotcgrand was last seen quitting 3 days and 13 hours ago.
04:51markomanok, I figured the error, maybe its again about macros. im using (ds/new* _type_) and I cant just get type from database.clj with the interface function... maybe I need to turn back and try importing type as a class...
05:00thorwilis there a nicer way to get the same result as with (defn to-int-or-nil [n] (try (Integer. n) (catch Exception e nil))) ?
05:03fliebelthorwil: What is wrong with that? Can n be anything?
05:04clgvthorwil: Integer/parseInt with surrounding try-catch is directly using java. but is it really nicer?
05:04thorwilfliebel: n is always a string
05:05fliebelIn weak typed languages you could just *use* it as an integer, and PHP would probably not even comply if it wasn't numerical.
05:05clgvthorwil: you can specify the radix when using parseint but probably you dont need that anyway
05:07thorwilit just feels clunky, having to catch an exception, instead of getting nil right away. but it's short enough and does the job
05:11clgvhow do I get the clojure 1.2.1 and clojure-contrib 1.2.1 with leiningen?
05:11clgvjust changing the version numbers does not work
05:14markomanhow can I map (into []) to each list element? im not sure how to pass function with arguments...
05:14clgvoh it works for clojure but not for contrib. so there might be noch contrib 1.2.1...
05:16markoman(map (fn [x] (into [] x) [...]) seems to work
05:17thorwilhow about (map #(into [] %) [...]), then
05:34markomanshorter :) how to you explain that # means a function with unlimited undefined (0-n) arguments? % is the first one?
05:39raekclgv: true. clojure 1.2.1 and contrib 1.2.0
05:40raek(the 1.2.1 version is just bugfixes)
05:41thorwilmarkoman: it's a macro that can often replace fn. but not wrapped, so no #() in a #()
05:42markomanok, cool
05:42thorwilmarkoman: % is the same as %1, the first argument. following are %2, %3 ...
05:43Chousukeand %& for the rest arg
05:43markomanin which format rest of the args are, btw?
05:43markomankw map?
05:43Chousukea seq
05:45thorwil,(#(type %&) 1 2 3)
05:45clojurebotclojure.lang.ArraySeq
05:49markomannicely proved. hmh... next im trying to figure out, how do I sort kw maps. I have [{:x 1 :order 0} {:x 2 :order 2} {:x 3 :order 1}] and would like get in ascending order by keyword order
05:52raek,(sort-by :order [{:x 1 :order 0} {:x 2 :order 2} {:x 3 :order 1}])
05:52clojurebot({:x 1, :order 0} {:x 3, :order 1} {:x 2, :order 2})
05:56raekoh. neat: https://github.com/technomancy/slamhound
06:10markomanthanks
06:18clgvis CCW 0.2.0 stable able to reformat my files?
06:46fliebelnice....
06:46fliebelJava HotSpot(TM) 64-Bit Server VM warning: Exception java.lang.OutOfMemoryError occurred dispatching signal Unknown Signal to handler- the VM may need to be forcibly terminated
06:56fliebelHas anyone figured out yet how to 'send' objects to a lazy seq? Probably something with promises.
06:58fliebel(map deref (repeatedly promise)) smething like that probably.
07:00raekfliebel: http://clj-me.cgrand.net/2010/04/02/pipe-dreams-are-not-necessarily-made-of-promises/
07:01raekfliebel: http://clj-me.cgrand.net/2009/11/18/are-pipe-dreams-made-of-promises/
07:01raekyou need some queue-like thing
07:01fliebelthese sounds familiar… I'll read them (again), thanks :)
07:01raek...which can be made with promises
07:01fliebelraek: Meh, I'm fed up with queues, I've been fighting them for days.
07:02raekhis LinkedBlockingQueue version is really elegant
07:03raekI love that you get synchronization automatically by only exposing the "reading end" as a lazy-seq
07:03fliebelraek: Okay, now try that with a PriorityBlockingQueue, and then with a SynchronousQueue :(
07:04raekwhat are the problems with a SynchronousQueue?
07:05fliebelraek: Nothing, except that you can't use poll or offer, nor can you lock the queue.
07:07raekbut isn't the point of a SynchronousQueue that two threads *want* to block to transfer an object between them?
07:08raekI think they're called rendezvous in some languages
07:08raekwhy can't you lock it?
07:08fliebelraek: Yes, but I can't lock the whole queue to make sure I avoid racing conditions. So it's just another option that does not work.
07:09fliebelwell, if I lock it while putting, the getting function can never access it, thus the putter never finishes.
07:09raekdoes it use that object as a lock internally? if so, then simply do (let [lock (Object.)] (locking lock ....))
07:10raekI ran into something similar when I tried to lock an atom
07:10fliebel… I'm not sure I understand what you mean.
07:10raekyou can use another object as the lock instead of the queue
07:11raekin case the-queue-as-a-lock is already used internally in the queue
07:11fliebelyes, but does that help? For that queue to work, 2 objects *need* to access the queue at the same time.
07:12fliebelsince put will only finish once there is a get going on at the other end, and the other way around.
07:15clgvfliebel: you only want to resume the putting thread if the queue is empty again?
07:16fliebelclgv: No, I just want the putting thread to continue putting, but the taking thread needs to know when to stop.
07:16clgvso you need something like a EmptyWaitHandle.
07:17fliebeluhm, maybe?
07:17fliebel$google EmptyWaitHandle
07:17sexpbotFirst out of results is:
07:17clgvit has to wait for the queue to signal that it is nonempty
07:17clgvI know that the class name in .NET is WaitHandle - I don't know the java one
07:18clgvseems to be wait() notify() on a shared lock object in java
07:19fliebeltake already waits for non-empty, but when the putter is done, it might wait forever.
07:19clgvah ok, now I get it. so you need a timeout version of it?
07:20fliebelthat'd work, but also be slow and ugly. I'm trying to make it JustWork™
07:22clgvhumm you could try to couple two signals with an "or semantic" the second signal would be "putter done" which is raised when the putter calls a related method
07:23fliebelclgv: What I have now is that I use Thread/interrupt to quit the getter, but somehow it still hangs.
07:23fliebel*sometimes*!
07:23clgvfliebel: sounds ugly. isnt this usage of threads discouraged?
07:24fliebelclgv: Actually it sounds a lot easier to me than the signaling you described.
07:24clgvfor semantics of that signal coupling you can look at waithandle waitany in .net
07:24clgv$google c# .net waithandle waitany
07:24sexpbotFirst out of 886 results is: WaitHandle.WaitAny Method
07:24sexpbothttp://msdn.microsoft.com/en-us/library/system.threading.waithandle.waitany(v%3Dvs.71).aspx
07:25fliebeluh, okay.
07:25clgvoh different first result
07:26fliebelanyway, I'll try the agent hack first… Then I'll need to study the Java way of notifying and locking.
07:26clgvbut I guess it's complicated when you use the queue that hides it's own signaling for "non-empty" from you
07:27fliebelclgv: Actually, there is an isEmpty method...
07:27clgvfliebel: you can't do much with it without timeouts since your getter thread will sleep...
07:28fliebel:( difficult stuff, this non-clojure concurrecny.
07:31clgvah well not too much. isnt the java source accessible? the concurrent queue source shouldnt be that complicated
07:32clgvI did write one myself sometime ago maybe not feature complete to the one you are using there ;)
07:33clgvyou just need a list some access locking and the previously discussed signals
07:34fliebel...
07:53fliebelWhen a future has an error, is it done or canceled?
07:55raekit is done
07:57fliebelokay, is there a non-blocking deref, or should I just ask the future if it's done?
07:57fliebelOr is there something like agent-errors for futures?
07:57raekfliebel: there is a deref with timeout in 1.3.0
07:58raekbut you can use the underlying .get directly
07:58fliebelI need to see if a future has errors without blocking it.
07:58raekif future-done? returns true, then you will never block on deref
07:59fliebelright, so (when (future-done? fut) @fut) will do just fine.
07:59raekand the deref will throw a ExecutionException with the exception as its cause
07:59raekhttp://download.oracle.com/javase/6/docs/api/java/util/concurrent/Future.html
08:04fliebelOh, nice :) I made seque work, except for 2 edge cases. 1) the seq throws an error 2) the provided queue already contains items.
08:08markoman(assoc (ds/query :kind Form) :dtype :form) says: clojure.lang.LazySeq cannot be cast to clojure.lang.Associative
08:09markomanis it possible to update lazy sequence similar way to assoc?
08:15clgvmarkoman: answering to the exact question - I don't think so, since a sequence is not a map
08:17markomanhmh... is there any way to add information on lazyseq and keep all the other information unchanged?
08:17clgvmarkoman: metadata maybe?
08:18markomansequence is similar to map form for example: #:Form{:id "form1"} where I need to set :dtype
08:18fliebelThis is starting to look really silly… I implemented a half ad-hoc, broken, informally specified, slow, bug-ridden queue to work around the problems my queue have.
08:20avyskmarkoman: I'm not sure I've got your question, but maybe lazy-cat is what you're looking for?
08:20clgvmarkoman: I didn't understand your last comment neither
08:21markomanwell the datastore query gives this #:Form{:id "form1"} and I need to manually add :dtype so the expected return is -> #:Form{:id "form1" :dtype :form}
08:22markomanbut I cant do assoc because of datatype im not familiar with
08:23dnolenmarkoman: how can the ds query give something that looks like that if you said it's returning a lazy sequence?
08:23markomanhmh, i may have understood error message wrong way
08:26markomanjava.lang.ClassCastException: clojure.lang.LazySeq cannot be cast to clojure.lang.Associative (NO_SOURCE_FILE:0)
08:26markomanwhen I try to do this: (assoc (ds/query :kind Page) :dtype :page)
08:26dnolenmarkoman: sounds like the query is probably returning a lazy sequences of *maps*
08:27dnolen(map #(assoc % :dtype :page) (ds/query :kind Page))
08:27markomanand (assoc (ds/query :kind Page) gives (#:magicforms.database.Page{:id "page1"}) oh yes
08:29markomanI got it now. huh, its a whole new thing to deal with sequences
08:31freiksenetI've replaced (list ...) with (pvalues ...) at one place and no program doesn't terminate (so it produces the result, but it doesn't end), what can cause that behaviour?
08:31freiksenetnow program*
08:31clgvmarkoman: you should get and read one of the clojure books ;)
08:33markomanI've been passing that joy to summer time reading ;)
08:33freiksenetwhat I mean by "doesn't terminate" means it never exits, it finishes and then just hanges there until you C-c
08:33freiksenetuh, sorry for my today's english, I have bad flu %)
08:38clgvfreiksenet: sounds like a thread is keeping the program "alive"
08:38freiksenetclgv: that's strange, cause it already printed the output of the program, so why would thread be still alive?
08:39clgvfreiksenet: humm maybe the pvalues spawns some non-background thread that doesnt exist? do you have a minimal example where the error happens?
08:41freiksenetit was something like (apply function (list ..)) and became (apply function (pvalues ..))
08:41clgvI cant try it without having a complete minimal example ;)
08:42freiksenetok, just a moment
08:49raekfreiksenet: you could try calling shutdown-agents at the end of the program
08:49raekpvalues uses the same threads as agents
08:50freiksenetok, I'll try that
08:52freiksenetraek: ok, that worked
08:52freiksenetthanks
08:55freiksenetmm, one question. is it possible to ask clojure to muffle warnings?
09:01fliebelfreiksenet: You mean try/catch?
09:01fliebeloh, no, I see what you mean, I think...
09:01freiksenetfliebel: no. CL has *muffle-warnings* special variable
09:01freiksenetwhich, well, muffles warnings :D
09:01freiksenetwhen you set it to true
09:02freiksenet(I know it's a bad style, but I don't have time to fix import warnings now and I don't want them to show up in final jar)
09:02fliebelNothing like it, as far as I know.
09:03fliebelDoes anyone know if the deref timeout is already in some snapshot or alpha?
09:05raekfliebel: https://github.com/clojure/clojure/commit/84710838d6996d9144d83c5b659bdeda4c656100
09:05raekit should at least be in the SNAPSHOT version, if I understand the process correctly
09:06fliebelSo that would be…. [clojure "1.0.3-SNAPSHOT"]?
09:07fliebeluhm, switch these numbers
09:07fliebelI think someone said the other day that snapshot builds are no longer on the default repo.
09:08fliebelraek: How can I tell from that commit if it's in a alpha build?
09:12raekdon't know a convenient way
09:12raekthere are tags for the alphas
09:13raekalso: semi-related http://corfield.org/clj/index.cfm
09:13fliebelraek: No snapshots there.
09:13raek[org.clojure/clojure "1.3.0-SNAPSHOT"]
09:14raekthus the "semi-"... :P
09:14fliebelah :)
09:14raek(I find that page valuable for getting a clear view of the current versions available=
09:15raekand this hasn't been updated in a while: http://build.clojure.org/snapshots/org/clojure/clojure/
09:16raekso the snapshots probably live somewhere else nowadays
09:16fliebelraek: That is what I said, someone mentioned them being moved elsewhere.
09:18fliebel"stuartsierra: and http://build.clojure.org is no longer the host for the latest snapshots."
09:20fliebeland http://groups.google.com/group/clojure-dev/browse_thread/thread/84a18aa37e541981
09:20hugod_they are on the sonatype repo I believe http://oss.sonatype.org/content/repositories/snapshots
09:22fliebelhugod_: Indeed, thanks :)
09:27fliebelWaa, my cake is slow. It's been like that for weeks now. How can I get lein standalone to run in 1.3?
09:28raekstandalone? lein repl outside a project?
09:28markomanhow do you actually see, if item is on list? like (contains? [:form :page] :page)
09:28fliebelraek: jep. just to play around with some files and stuff.
09:28dnolenmarkoman: contains? is for checking keys, you want some
09:29dnolen,(some #{:page} [:form :page])
09:29clojurebot:page
09:29raekmarkoman: use (some #{the-element-you-are-looking-foor} coll). "contains?" should be read as "has-key?" and only makes sense for maps, sets and vectors (where key = index)
09:30markomanok, thanks
09:30raekfliebel: I think you need to make a project to control that. iirc, you get whatever clojure version leiningen uses internally if you do lein repl outside a project
09:31fliebelokay...
09:31raek(it is not as configurable as cake's global project yet)
09:31fliebelI'd rather have cake work again…
09:32fliebelwaaa, deref doesn't even have the timeout option in the snapshot. It's not my day today...
09:40clgvis there a way to ":use" the methods of an entire protocol within the ns-statement?
09:53gfrlogIf I want to have a couple sample files for my automated tests to read, where should I keep them? I was looking at the directory defaults in leingingen and saw src/test/resources, so I figured that would be sensible, but I'm not sure how to read files from there
09:53gfrlog(slurp) doesn't seem to work, while it _did_ work when I kept the file in the root of the project
09:59joegalloslurp take a file path as an argument, if it's a relative path, then it's relative to the cwd -- which is the root of your project. so, if you move the file into src/test/resources, then you'll need to prepend that to the path. have you done so?
10:02gfrlogno, I thought there would be a cleaner way to do it having to do with the classpath
10:02gfrlogI know a relatively absolute filepath would wark
10:03fliebelHow cna I use object.wait in clojure? Since there is no synchronized.
10:03gfrlogmy foggy impression was that the resources directory was special somehow
10:03TimMcgfrlog: I put my automated test files in ./res in my project folder.
10:04TimMclein test -> read from ./res/foo.s
10:04joegallogfrlog: you can (slurp (resource "some/thing/on/classpath")), or some variation on that
10:04joegallomight take a little tweaking
10:05gfrlogjoegallo: that function isn't in core -- are you thinking of something in core or somewhere else?
10:05joegalloclojure.java.io
10:06gfrloghmm
10:07raekfliebel: (def o (Object.)) (future (locking o (.wait o) (println "boo!")))
10:07gfrlogman this repl is still buggy. Aren't open source technologies supposed to fix themselves if I just wait long enough?
10:07raek(lokcing o (.notify o))
10:08fliebelraek: It works, but how can the notify execute if the future is locking o?
10:08raekfliebel: when it waits, it does it outside the monitor
10:08raekfliebel: http://upload.wikimedia.org/wikipedia/en/f/f5/Monitor_%28synchronization%29-Java.png :-)
10:09fliebeloh, neat
10:09gfrlogjoegallo: I think that is probably exactly what I was looking for, thanks
10:09gfrlognow if only src/test/resources were on the classpath...
10:09raekthis is documented in the javadoc for java.lang.Object
10:09raekgfrlog: leiningen puts resources/ on the classpath by default
10:10raekgfrlog: but if that directory did not exist when the clojure instance was started, you need to restart
10:10gfrlograek: the sample-project.clj claims that it adds "src/main/resource" and "src/test/resource"
10:10joegallogfrlog: np, have fun
10:10gfrlogbut based on reading the system property I think it only adds "src"
10:11joegallogfrlog: you would need to add those entries to your project.clj in order for that to take effect
10:11gfrlogoh wait I think I may have pluralized it...
10:11raekgfrlog: no, that's an example of how to override the default with something elese
10:11joegallothe sample is just full of examples, not what is implicitly done on your behalf.
10:11gfrlogit has the comment ";; If you'd rather use a different directory structure, you can set these."
10:12raekgfrlog: it adds src/, classes/, lib/<all jars here>, resources/ and test/
10:12gfrlogso if the examples given aren't defaults, then I'm confused
10:14qbgI'm working on a fork of Clojure that tries to improve the error messages, and I'm wondering if filtering the stacktraces (more than what pst does) would be useful. Any suggestions?
10:14gfrlogyep, setting it in project.clj explicitly worked.
10:14gfrlograek, joegallo: thanks
10:19TimMcqbg: pst?
10:20qbg(doc clojure.repl/pst)
10:20clojurebotTitim gan éirí ort.
10:20qbg,(doc clojure.repl/pst)
10:20clojurebotExcuse me?
10:20TimMcOK, cool.
10:20qbgIt is accessible in user in 1.3 at least
10:29powr-tochas anyone got "checkout dependencies" working in leiningen? despite having a checkouts directory it keeps going to clojars for my lib
10:30raekpowr-toc: it needs to fetch the lib in order to fetch its dependencies
10:31TimMcqbg: I have `make test` -> `lein test | grep -v "at clojure"` or something. :-)
10:31raeka checkout replaces that project later
10:31powr-tocraek, but it has the project.clj in dependencies/my-lib
10:31powr-tocso does it really need to fetch it?
10:31raekhrm, true.
10:32powr-tocit seems to almost work if I don't list the project as a :dependency in project.clj, but then when I uberjar it doesn't get included
10:33raekwhat I do know is that the checkouts feature is made for the situation when the project does exist in a repo (maybe the local repo)
10:33powr-tocahh ok, I'll try that
10:34raekyou can do a lein install in the other project so that maven becomes aware of its existance
10:34powr-tocraek, yeah, thanks for that... I have a feeling this might work now
11:04mprenticecan someone point me to up-to-date instructions on getting clojure, slime, and common lisp to work, or help me out? i have a git clone of technomancy's slime, version 2009-10-15, git clones of swank-clojure and clojure-mode
11:05mprenticei am running a project with lein swank, and when i connect i get a version mismatch: swank version 20100404
11:05mprenticealso, when i quit clojure and then start another instance and connect with slime-connect, i get: "error in process filter: Symbol's function definition is void: slime-autodoc-mode"
11:11mprenticeoops, my mistake. i had setup slime-repl instead of slime-fancy, so that's the last error. still get the version mismatch but i can live with that.
11:18edwWhat's slime-fancy?
11:21mprenticeedw: it auto-loads some slime plugins. i'm fuzzy on which ones exactly.
11:21mprenticeedw: one of them is clearly autodoc :P
11:22edwThanks. My impatience trumped my laziness and I went to Google...
11:25fliebelHah! Can anyone confirm I'm not daydreaming, and that this actually works? https://gist.github.com/934781 I ended up using an ad hoc, informally -specified, bug-ridden, slow implementation of half of BlockingQueue, but it seems to work.
11:30clgvfliebel: woah thats huge ;)
11:31fliebelclgv: It is. If you think you can do better… ;)
11:32clgvfliebel: no time for it now. I just did a major refactoring and have to get it to work now
11:32fliebel:)
11:33clgvlol
11:37fliebel~CL
11:37clojurebotYou just made an ad hoc, informally -specified, bug-ridden, slow implementation of half of that.
12:04clgvlol what?
12:04bhenryhttps://gist.github.com/a09054cec2522364dea9
12:05bhenryfor those of you using emacs
12:09sritchiehey all -- if I'm using the for macro to read through a bunch of lines in a file, what's the most idiomatic way to maintain a counter to keep track of line number?
12:10sritchiethe main task here is -- iterate through a text file, appending line number onto the beginning of each line
12:10Chousukedon't use for :/
12:10Chousukefor is lazy
12:10clgvsritchie: you could use map-indexed
12:11sritchieI was using (doseq [line (read-lines old-file)] (println (str "counter! " line))
12:11sritchiewith my output writer pointing to the file
12:12sritchieoh, I see what you mena
12:12sritchiewrap (read-lines old-file) in a call to map-indexed, since they're both lazy
12:13sritchiethanks guys
12:19pdk,(* 38 0.15)
12:19clojurebot5.7
12:21pdk,(- 39 (* 39 0.15))
12:21clojurebot33.15
12:58kaw_Hi, I'm trying to use slime and leiningen for playing around with Clojure.. is "lein swank" supposed to make my code available at the slime REPL? I can't find my namespaces with (all-ns), am I missing something?
12:59technomancykaw_: no, all-ns only gives you what's been loaded already.
13:01bhenrykaw_: in your repl (use 'your-ns) to make your code available at the repl
13:01kaw_Ah, thanks, that works
13:02carllercheIs it normal that when I delete a function and run C-c C-k the function is still there?
13:02bhenrycarllerche: yes
13:03carllerchebhenry: is there a way to get the compilation to fail? When i rename a function, i'm tending to miss some calls.
13:03bhenrycarllerche: http://clojuredocs.org/clojure_core/clojure.core/ns-unmap
13:05bhenrycarllerche: either use remove-ns or ns-unmap to get the unwanted things out of what's loaded.
13:05carllerchethanks
13:31manutter,(doc ns-unmap)
13:31clojurebot"([ns sym]); Removes the mappings for the symbol from the namespace."
13:58gfrlogI wish stack traces came out backwards
14:01bhenrygfrlog: they are latest first. that is backwards.
14:01gfrlogbhenry: I wish they weren't backwards then.
14:02gfrlogbecause I always have to scroll up to see what's going on
14:02fliebelgfrlog: One, moment, I'll write you one..
14:02gfrlogfliebel: a lein plugin?
14:02amalloythey come out half-backwards. reversing them would make the problem worse, not better
14:03fliebelgfrlog: Nope… I'm going to do what amalloy says :)
14:03gfrlogfliebel: making it worse rather than better?
14:03amalloyyou rarely want the top-most line; the most interesting stuff comes after the last occurrence of "Caused by"
14:03fliebelgfrlog: Yea...
14:04gfrlogI bet a lein plugin could filter out non-user code
14:04gfrlogthen a second plugin could fix the bug that caused the stacktrace
14:04amalloy$google clj-stacktrace
14:04sexpbotFirst out of 382 results is: mmcgrana/clj-stacktrace - GitHub
14:04sexpbothttps://github.com/mmcgrana/clj-stacktrace
14:05amalloyhelps at least a little
14:05gfrlogah this is what the ring server errors go through
14:06gfrlogamalloy: thanks
14:06fliebelHm, something like… (reverse (line-seq (with-out (.printStackTrace *e))) only with-out does not exist, and Java probably does not obey *out*
14:10gfrlogjava does not obey *out*
14:10gfrlogit is disobedient wrt *out*
14:10fliebelI know… ah! moment
14:13fliebel(.setStackTrace *e (into-array (reverse (.getStackTrace *e))))
14:14fliebelgfrlog: ^^
14:15gfrlogyep
14:37kaw_Do I need to do anything special to get my interactive session reloaded correctly after changing a record type in the source? I'm getting errors like these in the REPL, but not when compiling manually: http://paste2.org/p/1385852
14:38kaw_Well, not in the REPL but after C-c C-k in Emacs
14:51amalloykaw_: i expect you have to C-c C-k in the code defining the record and the code using the record
14:53kaw_Yeah, those are both in the same file
15:13stirfootechnomancy: do you have any suggestions for gettin *print-suppress-namespaces* working with macro expansion: C-c RET and C-c M-m
15:14mprenticeok, dumb question, probably a brain fart on my part. i have a list of maps sorted by :id and i want to keep the maps with unique :id. i think it's like distinct but takes a predicate. is there such a function?
15:15hiredmangroup-by :id and take the the first from each group
15:16mprenticehiredman: ah, thanks. sorry for the dumb algorithm question
15:16dnolenstirfoo: are you using swank-clojure?
15:16stirfoodnolen: yes
15:17stirfooit works fine except for the namespaces gettin printed
15:20amalloyif they're already sorted by :id you can use partition-by instead of group-by
15:21stirfoowell that and the expansion is not getting pretty printed
15:22mprenticeamalloy: thanks. since the list is initially unsorted, i removed the sort and just use group-by
15:30bhenry1mprentice: is there any method to which map you want to keep? or just any one of the maps with id x?
15:31mprenticebhenry: any of them. i have a bunch of tokens from a tokenizing process, and a bunch of entities from a dictionary process, and i want to smush the tokens if they are in the range of an entity.
15:32dnolenstirfoo: it should definitely get pretty printed.
15:32mprenticebhenry: i may be rethinking how i do this. it's gotten so i've gone through doing this in two different ways already and each time i forget and re-invent what i'm doing :(
15:32dnolenstirfoo: what version of clojure?
15:52gfrlogis c.c.mock popular? I'm looking at the code and I think the arg-validation feature is limited to fixed-arity fns
15:53gfrlogwouldn't be too hard to patch though...
16:05stirfoodnolen: 1.2.0, sorry, I stepped out for a bite to eat
16:06stirfooI used package.el to install slime, slime-repl and clojure-mode and I think I just cloned technomancy's git repo
16:08dnolenstirfoo: hmm, is contrib on your path as well?
16:09stirfooI *think* it is ...
16:09dnolenstirfoo: is it in your lib dir ?
16:12stirfooI just required str-utils2 and it's working
16:13dnolenstirfoo: what version of clojure btw?
16:13stirfoo1.2.0
16:15stirfooI called swank.clj-contrib.macroexpand/macroexpand-all directly and it seems to branch if walk-enabled? and that depends on clojure.contrib.macro-utils
16:37manutterpart
16:37manutteroops
17:12seancorfieldsomeone was asking about snapshot builds:
17:12seancorfield:repositories {"sonatype" "https://oss.sonatype.org/content/repositories/snapshots&quot; }
17:12seancorfield,(+)
17:12clojurebot0
17:13gfrlog,(-)
17:13clojurebotjava.lang.IllegalArgumentException: Wrong number of args (0) passed to: core$-
17:14seancorfield,(*)
17:14clojurebot1
17:14seancorfield,(/)
17:14clojurebotjava.lang.IllegalArgumentException: Wrong number of args (0) passed to: core$-SLASH-
17:15seancorfield,(or)
17:15clojurebotnil
17:15seancorfield,(and)
17:15clojurebottrue
17:15seancorfieldhmm, ok, now that is a bit bizarre
17:16seancorfieldthis is all in response to jneira on twitter being surprised that (reduce + []) => 0
17:18gfrlogseancorfield: which one do you think is bizarre?
17:19seancorfield(and) => true... but now i think about it, it makes (some) sense
17:19gfrlogit's analogous to (+) => 0 and (*) => 1
17:19gfrlogit lets you define it recursively with no-args as the base case
17:19seancorfieldyeah, like i say, once i thought iabout it, it makes sense
17:20gfrlogit also lets you specify any number using just parentheses, + and *
17:20amalloy- and / don't have "obvious" meaningful defaults for the zero-arg version
17:20gfrlogwhich is good for making unsuspecting observers think you're some kind of crazy magician
17:20seancorfieldno, that i expected...
17:21amalloyhere's a good joke: ##(#'and true false)
17:21sexpbot⟹ true
17:22gfrlogwhat happens when you eval a var?
17:22amalloy&(#'+ 1 2 3)
17:22sexpbot⟹ 6
17:22hiredmangfrlog: pretty sure vars eval to themselves
17:23gfrloghiredman: I would have said that too until ##(#'and true false)
17:23sexpbot⟹ true
17:23amalloythat's why it's a good parlor trick
17:23gfrloggotta start questioning somewhere
17:23amalloyyou have to learn some internals to see why it happens
17:24hiredmangfrlog: vars dispatch fn calls to the value they hold
17:24hiredman,((resolve '+) 1 2)
17:24clojurebot3
17:24hiredman,(resolve '+)
17:24clojurebot#'clojure.core/+
17:25gfrlog,((resolve 'and) true false)
17:25clojurebottrue
17:25gfrlog,(#'and true false)
17:25clojurebottrue
17:25gfrlog,(#'and false false)
17:25clojurebottrue
17:25raekah, invoking the macro as a function...
17:25gfrlogoh right
17:25hiredman,(macroexpand '(and A B))
17:25clojurebot(let* [and__3468__auto__ A] (if and__3468__auto__ (clojure.core/and B) and__3468__auto__))
17:26amalloyraek: spoilsport
17:26raek,(#'and nil nil 'x 'y)
17:26clojurebot(clojure.core/let [and__3468__auto__ x] (if and__3468__auto__ (clojure.core/and y) and__3468__auto__))
17:26gfrlogthen why does it return true and not an s-expression?
17:26seancorfield,#'and
17:26clojurebot#'clojure.core/and
17:26seancorfield,and
17:26clojurebotjava.lang.Exception: Can't take value of a macro: #'clojure.core/and
17:26seancorfieldah...
17:26amalloygfrlog: because i passed it exactly two arguments, just like ##(and) with no args returns true
17:26sexpbot⟹ true
17:26raekthe first two arguments are special. the rest are passed to the macro normally
17:27amalloy&(#'and true false 'some-val)
17:27sexpbot⟹ some-val
17:27amalloy&(#'and true false 'some-val 'another-val)
17:27sexpbot⟹ (clojure.core/let [and__3468__auto__ some-val] (if and__3468__auto__ (clojure.core/and another-val) and__3468__auto__))
17:28gfrloghmmm
17:28amalloythe fact that i pass booleans for the first two args is what makes it misleading - the and-macro doesn't read those args at all
17:28amalloy&(#'and)
17:28sexpbotjava.lang.IllegalArgumentException: Wrong number of args (0) passed to: core$and
17:31chrissbxHow do I turn a file or string into a java.io.Reader ? (And how do I figure such things out myself if I don't know java already?)
17:32raekchrissbx: clojure.java.io/reader is very useful. it accepts Files, Strings (interpreted as filenames), Sockets, etc
17:34amalloychrissbx: clojure.java.* is good in general for covering up some of the most-inconvenient java bits
17:34chrissbxok, thanks
17:35raekchrissbx: but it is probably good to at least have scanned through the javadoc for java.io.Reader/Writer/InputStream/OutputStream
17:36chrissbxWhat's the best way to read the javadoc? I'm using emacs, not eclipse.
17:36raekif all you do is reading lines from text files, then you might not need to touch those directlyt
17:36raekI usually just look at it in my browser (http://download.oracle.com/javase/6/docs/api/)
17:37chrissbxok
17:37raekbut if anyone has a good trick for how to do it in emacs, I'm listening... :)
17:38technomancyraek: I think stuarth wrote something to pull that up in w3m
17:39raek(there's also clojure.java.javadoc/javadoc to display the javadocs for something in the browser)
17:40hugod_slime-javadoc from http://bc.tech.coop/blog/081120.html
17:42technomancysucks working in a language without docstrings =\
17:42chrissbxI want to parse a file containing clojure code, i.e. (read (open "path")) where I'm missing the open part. |read| wants a PushbackReader.
17:42chrissbxBTW how do you quote symbols in clojure? |foo| is Scheme syntax.
17:42gfrlogtechnomancy: but I'm sure the language has macros right? so you can add them easily?
17:43chrissbx(That is, "|foo|" is the same as "foo" in Scheme, and "|foo bar|" is parsed as 1 symbol; hence the || can be useful to distinguish symbols from other stuff in normal text.)
17:44gfrlog,'"long symbol"
17:44clojurebot"long symbol"
17:44gfrlognope
17:44gfrlog,(symbol "long symbol")
17:44clojurebotlong symbol
17:44gfrloghmm
17:44chrissbxYeah, but something straight-forward for human consumption.
17:44gfrlog,'long\ symbol
17:44clojurebotlong
17:44gfrlogI got nothing
17:44chrissbxIn CL, one would upcase the symbol to differentiate it.
17:45gfrlog,(doc read-string)
17:45clojurebot"([s]); Reads one object from the string s"
17:45gfrlogthat oughta do for your other question
17:46chrissbxYeah, only one of them.. also, I need location information, not sure that's in the result of the above.
17:46gfrloglocation information? like filename and line number?
17:46chrissbxyes
17:46chrissbxand column, too
17:47chrissbxWhy is http://clojure.org/reader not giving or linking the answers to all these questions?
17:51hiredmanchrissbx: the clojure reader doesn't make file and line numbers available for symbols
17:51raekchrissbx: open = clojure.java.io/reader
17:52hiredmanmight be an interesting patch
17:52hiredmanI believe the current reader just adds file and line number information to lists
17:52chrissbxraek: no, since read doesn't work on the result of that
17:53gfrlogeven if read or read-string will add line numbers, how would you tell it the filename?
17:54chrissbxhow "how"? It would be kept as a field in the reader instance, for example, and then copied by read from there.
17:55gfrlogwhat's the simplest way in clojure to create a custom exception class so that I can catch my own exceptions? Having a separate file/namespace with :gen-class seems like a lot...
17:55gfrlogchrissbx: I wasn't asking you, sorry
17:55chrissbxAha. Anyway I'd be fine with just line/col information, I could then add the file myself.
17:57chrissbxhiredman: why not? Does it make them available for all the other objects?
17:58chrissbxah sorry, missed your 2 subsequent statement
17:58chrissbxs
17:59chrissbxWell, how does the clojure system itself track location information?
17:59gfrloggiven that throwable is a class, I'm not sure I can do it with reify or deftype...
17:59hiredmanchrissbx: doesn't
18:00chrissbxWell, I've not seen much help from slime backtraces, yeah, but that doesn't mean it doesn't track it, right?
18:00chrissbxAnd I think at least the line number is being output *sometimes*
18:00hiredmanthe line number you see is from the list form
18:01hiredmanthe list (/ 1 0) is read in and gets a line number, and that line number is what you see in the divide by zero exception
18:02gfrlog,(meta #'cons)
18:02clojurebot{:ns #<Namespace clojure.core>, :name cons, :file "clojure/core.clj", :line 22, :arglists ([x seq]), :doc "Returns a new seq where x is the first element and seq is\n the rest.", :added "1.0"}
18:02gfrlogso the eval function adds it to the var metadata from the list?
18:03hiredmanno, eval has nothing to do with it
18:04gfrlog the reader produces lists with metadata, which eventually somehow becomes metadata on the vars?
18:04hiredmanyes
18:05hiredmanthe compiler copies from the reader metadata on (defn cons ...)
18:05gfrlogman there's so many pieces
18:14chrissbxI'm considering writing an interpreter for Clojure, to get around the problems with lost context information etc.; is there anyone who might be interested in this, who I should contact?
18:16hiredmanchrissbx: why do it as an interpreter? just add what you want to the reader and the compiler
18:17chrissbxhm. I expect a mess there :~)
18:18chrissbxWell I'd reuse (and extend if necessary, but I suppose it's not) the reader.
18:18amalloywriting an interpreter will be much messier, i suspect
18:19chrissbxIt would only be my own mess :D
18:20chrissbxAlso, an interpreter is rather easy to write, the debugging features are likely the most involved part, and those are what I'm into, so the overhead might actually be so low that it's going to be easier than extending the compiler, and offer more possibilities.
18:20amalloyyou want to write, maintain, and debug a whole interpreter because of a small feature you feel is missing from the compiler? that sounds like a bad case of not-invented-here; surely there's something more productive you could do
18:21gfrlogif you're going to do it, at least do it on a totally different platform. Erlang? javascript?
18:21hiredmanthe first thing you need is a reader that keeps column information
18:21chrissbxAs I said, if it's more lines to write in the compiler than to make an interpreter?
18:21chrissbxAs I said, the reader is not the issue.
18:21chrissbxIf the reader is keeping enough location info for clojure, then I'm fine with that.
18:22gfrlog,(meta (read-string "(foo)"))
18:22clojurebotnil
18:22chrissbxAnd if it really doesn't keep col information then I'd extend it with that, hopefully that would work?
18:22chrissbxAnd, I'd have to do that anyway, even when extending the compiler, so that's beside the point.
18:24chrissbxgfrlog: it has to be written in Clojure so that it can call into compiled clojure code;
18:24chrissbxand Java code;
18:24chrissbxI don't want to reinvent the whole Clojure ecosystem!
18:24hiredmanchrissbx: do you think I am deceiving you when I say it doesn't?
18:26chrissbxhiredman: deceiving? Nah I just don't expect it. But if you're sure, so be it.
18:57kaw_I think I want to make a telnet-like interface for my code (for multiple users), can anyone recommend a high-level module for doing that?
19:05technomancykaw_: clojure.contrib.server-socket worked for me
19:05technomancyclojurebot: google clojure mire
19:05clojurebotFirst, out of 74 results is:
19:05clojurebottechnomancy/mire - GitHub
19:05clojurebothttps://github.com/technomancy/mire
19:06technomancy^^
19:07kaw_Thanks, I'll look at that
19:52SomelauwHi, should clojure be build on pypy instead of java?
19:54RaynesHi. No.
19:56SomelauwSince pypy is more dynamic and such than java.
20:00TimMcSo is JS. What's your point?
20:00brehautSomelauw: clojure has already worked around the discrepencies between its more dynamic nature and the JVMs more static nature. is there really much to gain vs the loss of ~20 years of VM optimisation?
20:01brehautSomelauw: also, clojure is gaining more static behavior over time too
20:19amalloyargh. how do i get access to GET parameters in compojure? i can find my POST params, and anything encoded into the URL itself like /id/10, but i want query params after the ?
20:20hiredmanI think ring makes them available as :query-params
20:21hiredmanor, actually, it has :query-string in the spec, you use middleware to turn them into a map
20:21amalloyhiredman: that's a keyword. so wrap-params adds a :query-params key to the request map?
20:21weavejesterYou can just reference them directly as parameters
20:22technomancyweavejester: hey; having better luck with slamhound 1.1.1?
20:22weavejesterRing adds three keys, :form-params, :query-params and :params. The :params key is the merged map of the previous two.
20:22weavejestertechnomancy, I've yet to try it :)
20:22amalloyweavejester: so (GET "/url/:someparam" [someparam otherquryparam] ...)?
20:22weavejesteramalloy, exactly
20:22amalloyi'm still a little vague about how the ring underlying stuff works; barely know my way around compojure yet
20:23amalloythanks. it was astonishingly difficult to find an example of that on the web
20:23weavejesterThe bindings, when in a vector, take it from the :params key, which includes *all* kinds of parameters
20:23weavejesterThere's some info in the "destructuring bindings" page on the wiki
20:25weavejesterhttps://github.com/weavejester/compojure/wiki/Destructuring-Syntax
20:25amalloyweavejester: that's...kinda true. you start from the assumption that we have a request map with :x, :y, etc in it
20:25amalloybut it isn't clear, for someone who has never used ring outside of compojure, how to get such a request map
20:26weavejesteramalloy, Yes... there's the first few chapters of a Ring book around that was cancelled by the publisher, and then released as CC - I'm not sure if anyone has turned it into HTML yet.
20:26weavejesteramalloy, But in a nutshell...
20:26technomancythe book was canceled? =(
20:27weavejestertechnomancy, Unfortunately yes :(
20:27weavejesteramalloy, Are you familiar with the concept of handlers and request/response maps?
20:28amalloyweavejester: a little. i watched a few presentations on ring a while ago but haven't started using any of it until last week
20:28amalloyand i remember bits of it, but how compojure interfaces with ring is less clear to me
20:28weavejesteramalloy, Okay, so a basic "hello world" in Ring is (defn handler [req] {:status 200, :headers {}, :body "Hello World"})
20:29weavejesteramalloy, Basically a function that returns a response as a map
20:29amalloyright
20:29amalloyand takes a request as a map
20:29weavejesterYep. But usually you want to respond to different routes
20:29weavejesterSo in pure Ring, you might write something like:
20:30weavejester(defn handler [req] (if (and (= :get (:request-method req)) (= "/" (:uri req))) ...)
20:30weavejesterSo you'd have this if-statement that would check to see if the request had the right request-method and path (URI)
20:31weavejesterWith me so far? :)
20:32amalloyrighto. and compojure (among other things), does the parsing and dispatching for me
20:32weavejesterYes, so Compojure does two things. The first is to add that if statement in that will only show the response if the conditions match
20:32weavejesterSo (GET "/" ...)
20:32amalloyright
20:32weavejesterIs the same as: (if (= :get (:request-method)) ... etc
20:33weavejesterThe second part is that you probably want to pull information out of the request
20:33weavejesterSo you can do that with a common binding, e.g.
20:33weavejester(GET "/" {params :params} ...)
20:34weavejesterThat's the same syntax you'll find in a let-form, or in function arguments
20:34amalloyexcept it's not wrapped up in a vector. is that because we're implicitly destructuring the ring request map?
20:34weavejesterCompojure has two forms of destructuring
20:35amalloy(and nothing else exists to bind to, so there's no need for a wrapping)
20:35weavejesterOne, the standard Clojure kind
20:35weavejesterAnd the second is a specific Compojure kind
20:35weavejesterWhen Compojure gets a vector, it knows to use its on destructuring
20:36weavejesterAs under normal circumstances, you can't destructure a request map using a vector destructure
20:36amalloyi see. so we get exactly one slot to destructure parameters in; a vector matches the :params key and does magic, while a map matches the ring request map and you do everything yourself?
20:36weavejesterSo using normal Clojure destructuring, you might write:
20:36weavejesterYes
20:37weavejesterVector = Compojure magic :)
20:37weavejesterWell, not magic, but it's own form of destructuring that's designed to pull information from parameters
20:37amalloyright, okay. and to expose those params to compojure's magic, i need to wrap-params around my handler, right?
20:37weavejesteramalloy, Yes. In the past, Compojure did that for you
20:38weavejesterBut that caused a few problems
20:38weavejesterSo instead I added compojure.handler/site and compojure.handler/api
20:38weavejesterWhich adds a whole bunch of common middleware for you
20:38amalloyyeah, i saw those
20:39weavejesterRing doesn't inherently know anything about parameters, cookies, sessions, or much of anything beside the raw request
20:39amalloyi stayed away because i didn't especially need any of them, and i'd heard someone saying something about some problem somewhere once (i can be more vague if you want)
20:39amalloyyeah, i get the concept of middleware
20:39weavejesterMiddleware is used to parse those additional pieces of information from the raw request
20:39amalloyoh, haha. apparently we are using handler/site and i just didn't know
20:39weavejesterThat's basically all there is to Compojure...
20:40weavejesterThe only other thing you need to know is "defroutes", which combines multiple handlers together
20:40AWizzArdweavejester: about the pure ring example from above: does ring only support one handler that is called for everything, and inside this one handler one needs to dispatch manually?
20:40weavejesterIf the first handler returns nil, it goes to the next one, and so on, until it gets a response map
20:41weavejesterAWizzArd, Yes
20:41AWizzArdah ok
20:41weavejesterAWizzArd, Multiple handlers that cascade are a Compojure-thing
20:41weavejesterOther routing frameworks like Moustache don't do that - they just have a static routing table (I believe)
20:41amalloyoh, i see. that's a surprisingly simple model of how defroutes works. i thought it was parsing the strings at macroexpansion time and expanding into a case form or something
20:41AWizzArdI am so used to the Compojure syntax that I never thought about how ring handles it under the hood.
20:42weavejesteramalloy, No, it's literally just this: (fn [request] (some (fn [handler] (handler request)) handlers))
20:43brehautweavejester: what do you mean by static routes table?
20:44weavejesterbrehaut, Well, like something that you can determine in one sweep. i.e. you could potentially use a static map of regular expressions for routing
20:44weavejesterbrehaut, Compojure doesn't actually know whether a route matches until it evaluates it.
20:44weavejestere.g. you could write:
20:45weavejester(GET "/:foo" [foo] (if (= foo "bar") "Hello World"))
20:45weavejesterAnd that would be the same as:
20:45weavejester(GET "/bar" [] "Hello World")
20:51brehautweavejester: the equivalent in moustache would be
20:51brehaut(app [foo] (fn [r] (when (= foo "bar") "Hello, World!")))
20:51brehautor perhaps more idiomatically (app [[name (fn [x] (= x "bar"))]] "hello")
20:51weavejesterbrehaut, Oh, does moustache cascade too? i.e. if one route doesn't match, it goes to the next?
20:52weavejesterweavejester, Or, rather if one route returns nil, it goes to the next
20:52weavejesterGah, I literally talked to myself there :)
20:53brehautweavejester it think so, let me just check
20:55weavejesterbrehaut, If that's the case, then withdraw my slanderous remarks about moustache ;)
20:55weavejesterAlthough a static routing table is probably going to be faster
20:55amalloyweavejester: perfect, i can read my GET requests! does compojure support the :or form for binding?
20:56weavejesteramalloy, You mean in vector format? No, but it supports :as
20:56weavejesterwhat's :or again?
20:56amalloyweavejester: default values
20:56weavejesteramalloy, Oh, now that would be an interesting feature to support
20:56weavejesteramalloy, But currently no, it does not.
20:56amalloy&(let [{k :k, v :v, :or {k 10}} {}] [k v])
20:56sexpbot⟹ [10 nil]
20:57brehautweavejester: it does cascade; the docs in the readme call it 'fall through'
20:57weavejesteramalloy, That could probably be adapted to Compojure
20:57weavejesterbrehaut, Ah, I stand corrected then
20:57amalloyweavejester: yeah, it seems like a feature you'd like to have
20:58weavejesteramalloy, Yes, although it would have to be well documented... Because :as binds to the request, and :or would have to bind to the parameters
20:59weavejesteramalloy, The problem with Compojure's custom syntax is that it needs to be subtly different from Clojure's bindings because it's binding against a map, rather than a seq
20:59amalloyweavejester: is the request map anaphorically in-scope with some default name, or can you only bind to it with :as?
21:00weavejesteramalloy, You need to explicitly bind it. Idiomatic Clojure tends to discourage implicit bindings.
21:00weavejestere.g. (GET "/" [x y :as request] ...)
21:00amalloyright
21:01weavejesterMaybe :as was the wrong keyword to use in this case
21:01weavejesterEverything else binds against the parameters, but :as goes one level up.
21:23amalloyweavejester: looking at http://data-sorcery.org/2009/11/29/incanter-webapp/, which seems to be using update-response from some dark corner of compojure. is that still a recommended usage? it doesn't seem very functional the way it's being used and documentation is lacking, suggesting it might be old
21:24amalloyall i'm really trying to do is take a ByteArrayOutputStream and serve it as my :body, but it's not entirely clear from reading that tutorial how to do that
21:25brehautamalloy: can you easily convert it to a file or inputstream ?
21:26brehautamalloy: look at png-response here http://raek.se/trattern/src/se/raek/trattern/graph.clj
21:26weavejesteramalloy, That's not really a recommended way of doing things. Ring usually just deals in InputStreams, Files, etc - things it can consume on its own terms.
21:27weavejesteramalloy, OutputStreams are obviously things pushed to the output
21:27amalloyweavejester: yes, it's not hard to turn it into an inputstream, of course, since it's a byte[]
21:28amalloyi just wasn't sure if ring supported that or what. looks like it does; thanks for the link, brehaut, that's perfect
21:29weavejesteramalloy, It's taking advantage of an internal Ring function, so it's not really recommended.
21:29brehautamalloy: https://github.com/mmcgrana/ring/blob/master/SPEC is your friend :)
21:30weavejesterOutputStreams are tricky in general, because they're not very functional
21:30weavejesterAn InputStream can almost be looked at like a lazy seq
21:30weavejesterOr could be converted into a lazy seq
21:31weavejesterIt has been proposed that Ring allow a function body
21:31weavejestere.g.
21:32weavejester{:status 200, :headers {}, :body (fn [out-stream] (.write out-stream ...))}
21:32weavejesterBut that hasn't been implemented... Partly because we might want to use a function body for asynchronous outputs.
21:33amalloyweavejester: it's no coincidence that scheme's version of lazy seqs is called streams
21:35weavejesteramalloy, Yeah - my point is that InputStreams are almost functional data structures, whilst OutputStreams are very much side-effectful
21:35weavejesteramalloy, And Ring tries to be functional in general
21:36amalloyyes. i'm trying to serve a png, is all, and incanter gives them out as outputstreams. it's not hard to flip them around, i just was a bit confused
21:46weavejestergotta go - bye
23:21seancorfieldamalloy: well, that is certainly some lateral thinking regarding problem #62!
23:21seancorfieldi solved it the obvious was and then went and looked at yours :)
23:21seancorfieldwas = way
23:21amalloyseancorfield: yeah, it turns out to be shorter than the lazy-seq way
23:22amalloyi think
23:22seancorfieldi wasn't sure, when i solved it, but can you recur from inside a lazy-seq?
23:22amalloyseancorfield: you can, but you don't want to
23:22seancorfieldthat's what i thought
23:23seancorfieldso i didn't try :)
23:23amalloyseancorfield: basically the recipe is (fn f [x] (lazy-seq (cons whatever (f more-whatever))))
23:24amalloyi abstracted over that with https://github.com/amalloy/amalloy-utils/blob/master/src/amalloy/utils/seq.clj#L32 and wind up with something that i think is more readable
23:30brehautamalloy: does 4clojure gist your solutions for you?
23:30amalloybrehaut: sure does
23:30brehautclassy
23:31amalloyeven classier now that we only gist them if you ask us to :P. github probably didn't even notice the ~2k gists i created that nobody ever looked at, but i felt bad all the same
23:31brehautheh
23:31brehautdoes it also tweet it if you choose?
23:32amalloybrehaut: it provides a link for you to tweet, with default text filled in
23:32amalloyi didn't want to fuss with oauth, so it can't tweet on your behalf
23:32brehautah nice
23:32brehauthaha
23:32brehautfair enough :)
23:35amalloybrehaut: you could find this out first-hand, you know
23:35brehautamalloy: sadly im busy with work and a couple of other projects ATM
23:36sritchiehas anyone run into this error with marginalia? clojure.lang.PersistentVector cannot be cast to clojure.lang.Symbol
23:36mreynoldsHave you guys thought about putting that site in the title? It looks pretty cool and could encourage nice discussions
23:44seancorfieldamalloy: i always forget you can simply name (fn)
23:45seancorfieldso i tend to do (letfn [(f [..] ..)] f) - i'll remember (fn f [..] ..) in future
23:46amalloyseancorfield: yeah, i hate letfn