#clojure logs

2009-07-16

00:30Knekkbleh, using the Emacs Starter Kit messes up my arrow keys
00:44ataggartis there a macro somewhere that will evaluate forms until one returns logical true?
00:45ataggartI seem to recall it, but can't find it
00:49ataggartaha! (some eval ['(foo ...) '(bar ...) '(baz ...)])
00:50skalnikLearning Clojure has given me a headache :D
00:50ataggartthats the feeling of new pathways being burrowed through your brain.
00:50skalnikyep!
00:51skalnikI've given up on Project Euler problem #2 for now :)
00:51ataggartdo you have a fib function?
00:52skalnikyep, that works :)
00:53skalnikI got stuck on trying to create a set of all the fib values under 4 million
00:53ataggart(reduce + (filter even? (take-while #(<= % 4e6) (fib-seq))))
00:53ataggartbooyah
00:54skalnikHaha
00:54skalnikWhy reduce instead of apply?
00:54skalnikWhat's the difference
00:54skalnik(if any)
00:55ataggartlazy
00:55skalnikah
00:55ataggartI think
00:55ataggarthmm
00:55ataggartno cant be about laziness
00:56ataggartsince you have to run thru the whole list
00:56ataggartbut "reduce" is more desciptive
00:56skalnikNow I just need to generate fib-seq
00:56skalnikI agree :)
00:57ataggartah ok, apply would work but only because + can take any number of args
00:58ataggartreduce is when you have a function that takes two args
00:58ataggartand crepeatedly applies it
00:58skalnikah ha
00:58skalnikSo what I want to do for fib-seq is (map #(fib %) (range 10)), but replace 10 with a very large number
00:59skalnikHowever, that seems wasteful
00:59ataggarthmm not sure how you're trying to apprach it. doesn't sound right
01:00skalnikso I have a fib function, so if you call (fib 3) it gives the third fibonacci number
01:00skalnikThe next step I wanted to do is create a set of fibonacci numbers less than 4 million
01:00hiredmansomeone should just write a canonical fib function so everyone can get on with their lives
01:01ataggartno one that needs to write one is doing for any reason than to learn. be gentle.
01:02ataggartskalnik, the thing is you don't want a function that takes an index
01:02ataggartyou want a function that will return a sequence of all values
01:03skalnikI suppose
01:03skalnikI haven't learned that much though, and I'm quite tired, plus I have surgery tomorrow, so I should be heading to bed :)
01:03skalnikThanks for the help ataggart
01:04skalnikalso, my method works, just seems improper to me :)
01:04ataggartyour intuition is correct ;)
01:09skalnikVery cool that no matter what large number I plug in, execution time is still roughly the same :)
01:09skalniknow, I really should be off to bed.
03:08hiredmanclojurebot: CA
03:08clojurebotCA is Contributor Agreement: http://clojure.org/contributing
03:27ataggartmailed mine today
05:27Jomyoot(with-query-results rs ["select * from blogs"]
05:27JomyootDoes that have lisp syntax for select statement?
05:27Jomyoothttp://en.wikibooks.org/wiki/Clojure_Programming/Examples/JDBC_Examples shows lips syntax for other commmadns but not select
05:55JomyootHow do I output Clojure's vector of int from Java?
05:56JomyootI am in Java. I want to output Vector of int, that is usable by Clojure
05:56jdz_use iterators?
05:56jdzor you can convert a vector to array
05:57JomyootClojure has [1 2 3 4]
05:57Jomyootvector
05:58JomyootI want to output [1 2 3 4] from Java object. that will work as [1 2 3 4] in Clojure with no conversion
05:58JomyootIs that possible?
05:58jdzwhat do you mean by "output"?
05:59Jomyootreturn
05:59Jomyootreturn from Java method
06:00jdzClojure vectors are Java objects (as any value in Clojure)
06:00jdzyou can pass them and retourn to any Java methods you want
06:00Jomyoothmm
06:00jdzI don't really understand what you want
06:01JomyootVector<Integer> vect= new Vector<Integer>(100); return vect;
06:01JomyootHow would Clojure see vect?
06:02jdzas an instance of Vector class
06:02jdzJava Vector class
06:02Jomyoothmm
06:03JomyootWhat would I output from Java then If I want Clojure to see as native [1 2 3 4]
06:03JomyootClojure's native
06:03rottcoddJomyoot: I think you want to create a clojure.lang.PersistentVector
06:03jdz,(class [1])
06:03clojurebotclojure.lang.LazilyPersistentVector
06:05JomyootIs it a standard practive to create a LazilyPersistentVector in Java. then return to Clojure?
06:05JomyootAs means of interop between java/clojure?
06:06jdzk
06:06jdzsorry
06:06jdz(that was C-x k in the wrong window)
06:07jdzJomyoot: you can use all the classes and interfaces in src/jvm/clojure/lang from Java
06:09JomyootArrays
06:09JomyootClojure supports the creation, reading and modification of Java arrays. It is recommended that you limit use of arrays to interop with Java libraries that require them as arguments or use them as return values.
06:09JomyootWhy ? what's wrong with using arrays?
06:11jdzthey are not persistent
06:11jdzand there is nothing wrong with them
06:11jdzyou just have to be very careful if you are using them
06:11jdzthat's why the rule of thumb of using them only for interop holds
06:13JomyootIs there easy ways to quickly convert array of int or vector of int to Clojure's native data?
06:16rottcoddvec
06:16carkor seq
06:17Jomyootseq
06:17Jomyooti want to make seq out of java array of vector
06:17Jomyootpossible?
06:17Jomyootmust be done manually?
06:18Jomyootor is there built in method
06:18carkjust use the seq function on your array
06:19Jomyoot seq also works on Strings, native Java arrays (of reference types)
06:19Jomyootwhat is reference types?
06:19Jomyootis int = reference types?
06:19jdz,(map (partial + 1) (seq (into-array [1 2 3 4 5])))
06:19clojurebot(2 3 4 5 6)
06:20carki think in this context reference type means objects as opposed to primitive values
06:20Jomyoothence array of integer will not work
06:20jdzi just showed you that it works
06:21cark,(seq (make-array Integer/TYPE 10))
06:21clojurebot(0 0 0 0 0 0 0 0 0 0)
06:21jdzin the example above a native Java array is created from Clojure vector, and then back to a sequence
06:21Jomyootis 1 2 3 4 in Clojure represented as int or Integer in Java?
06:21carkit depends
06:22carkthese are boxed before doing function calls, but could be native integers inside a function
06:22carkalso you can use native integers in java array
06:23carkso there would not be any boxing on function calls i guess
06:23ChrisPS,#'in-ns
06:23clojurebot#'clojure.core/in-ns
06:30carkJomyoot : native integer arrays do work with seq ...but the seq will contain boxed integer in the end
06:30cark,[(into-array [1 2 3 4 5]) (make-array Integer/TYPE 10)]
06:30clojurebot[#<Integer[] [Ljava.lang.Integer;@1b206f> #<int[] [I@ee90e9>]
06:31Jomyootwell then
06:31carkas you can see the second form creates an array of native ints
06:32Jomyootdoes it matter in clojure wheter it's native or boxed int?
06:32carkno more than it matters to java
06:32Jomyootdo clojure functions that require ints care?
06:32Jomyootwell then it does matter then
06:32carkthe only difference to my knowledge is performances
06:32Jomyootsome methods expect boxed some expect native
06:33Jomyooti would assume that most clojure functions expect either native or boxed but not both
06:33carkhave you an example of a java function that expects native ?
06:33carki'm not knowledgable at all on the java side of things, looks like something interesting to test
06:34jdzmany methods that accept characters also accept ints
06:34Jomyootmore methods expect int[] than Integer[]
06:34jdzlike, Character/isDigit or something
06:34Jomyootmore methods expect int than Integer as well
06:34Jomyootand all number literals in Java are native
06:34Jomyootnot boxed
06:35cark,(Character/isDigit (new Integer 3))
06:35clojurebotfalse
06:35carkthat's a boxed integer i'm passing there
06:36carkit is my beleif that the vm takes care of the conversion
06:36Jomyoot,(Character/isDigit 1)
06:36clojurebotfalse
06:37jdz,(Character/isDigit (int \5))
06:37clojurebottrue
06:37carkthough i don't think that applies to arrays
06:37keca,(Character/isDigit (int \5))
06:37clojurebottrue
06:37cark,(Character/isDigit (Integer. (int \5)))
06:37clojurebottrue
06:37grrrt,(int \5)
06:37clojurebot53
06:37jdz5 is *the* number :)
06:37keca,\5
06:37clojurebot\5
06:39grrrtisDigit has two implementations: one with a char and one with an int
06:39grrrtthe int version assumes the int you pass in is a unicode codepoint
06:39carkanyways the easy way to get an int[] array from a vector is this : (into-array Integer/TYPE [1 2 3 4 5])
06:43mikem`Hi, i'm trying to use a class from a jar file at the REPL in vimclojure, but I keep getting FileNotFoundException. I'm new to clojure and Java, can someone help me get started?
06:44grrrt if you get a FileNotFoundException, you're trying to load the class as a file?
06:45grrrtit should be on your java classpath, then you can use 'import' to use it in your namespace
06:45carkyou need to start java with the path to your jar added to the classpath parameter
06:46mikem`grrrt: I'm trying to load HttpPost from org.apache.http.client.methods (for example). I try (use 'org.apache.http.client) and get the FileNotFoundException
06:46mikem`ah, import... ok, let me give that a shot
06:46grrrtyeah use is for clojure namespaces
06:48mikem`grrrt: ok so I need to specify the .jar file on the classpath when I execute the nailgun server (for vimclojure). do I have to specify every .jar file or can I specify a directory with .jar files? the relevant jar files are in my pwd
06:49grrrtevery jar file
06:49carkyou can use wildcards for jvm 1.6
06:49grrrtah yes, that's true
06:49grrrtheh. spent too long on old jvms :(
06:50carkhere is how i start java on my current project : java -server -Xmx300m -XX:+UseParallelGC -cp c:/home/cara/clojure/WebTL/lib/*;c:/home/cara/clojure/WebTL/src/ clojure.main
06:50mikem`grrrt: ok, that's what I needed: use import and specify all jars on the command line. thanks!
06:50grrrtno worries, have fun!
06:50carknote that there is only one star
06:50mikem`cark: the wildcard doesn't seem to work for me
06:51carkwhat's your jvm version ?
06:51grrrtmikem`: if you do 'java -version', what do you get?
06:51mikem`1.6
06:51grrrthm
06:51carki swear it works =P
06:51mikem`1.6.0_14
06:51mikem`cark: I'm probably doing it wrong...
06:51carki have like 8 libraries in there in use for this project
06:52grrrtyou'd normally start your stuff from a shell script, ant file or maven file anyways
06:52grrrtyou wouldn't use a plain "java ............ clojure.main" command every time
06:52carkahwell the end product is an executable jar
06:53carkso there's no scrip, and no customer mess up =)
06:53grrrtheh
06:54mikem`cark: ok, with this command, everything works: http://dpaste.com/67796/
06:55carkgreat then =)
06:55carkthough it might be worth working out the wildcard thing to keep things simple
06:57mikem`ok, will try that after some food. thanks for the help so far
07:03grrrthmm there was a trick to using names that were defined as private, but what was it? I'm trying to access a def that is private from a test-is testcase (in a different file)
07:07grrrtAh, got it. to answer my own question: http://groups.google.com/group/clojure/browse_thread/thread/3835e5405ab930f6/
07:50JomyootCan file a.clj (:use b) and b.clj (;use a)?
07:51carknope
07:52carkthat's bad practice anyways
07:52Jomyootseriously
07:53Jomyoothmmm
07:55carkwhat you could do is this : load a, load b, both loaded from c ... c tells a where to find b's functions it needs, c tells b where to find a's functions it needs
07:57carkfor instance in a you would have (def my-proxy-to-b-hello) and from c you could (set! my-proxy-to-b-hello hello)
07:57cark(untested)
08:01carkor better yet, make A use B, then when A calls a function in B use a function parameter for the call B needs to do in A. you could use a map of functions if you want to pass several functions
08:22maaclUsing Emacs/Slime how do I identify the Clojure source line/function that resulted in a specific runtime exception? The traceback only seems to provide the Clojure .java file that failed (in this case the LazySeq.java)
08:23durka42try clojure.stacktrace/print-cause-trace
08:23dysingerI noticed clojure master on github has 'backtrace' too
08:23dysinger(not 1.0)
08:26maaclThat gives me java.lang.ClassNotFoundException: clojure.stacktrace (NO_SOURCE_FILE:0)
08:33maacldurka42: Should I do "clojure.stacktrace/print-cause-trace" at the Repl?
08:34durka42do (use 'clojure.stacktrace) first
08:34clojurebotclojure is like life: you make trade-offs
08:34durka42unless you don't have the latest clojure, in which case it might still be in clojure.contrib.stacktrace
08:36maacldurka42: ah, was in contrib
08:38maacldurka42: clojure.contrib.stacktrace/print-cause-trace -> #<stacktrace$print_cause_trace__4400 clojure.contrib.stacktrace$print_cause_trace__4400@5be2753e>
08:38Chouserwhoa. I hadn't noticed that stacktrace came in with gtic
08:38durka42apparently
08:39Chouserthat would explain that repl startup error I keep seeing but hadn't investigated yet...
08:39durka42:p
08:40maacldurka42: How is it supposed to be used ?
08:41durka42well, you cause an exception and then you can do (print-cause-trace *e)
08:50maacldurka42: does this have to be from the repl or can I do it from within a source file?
08:52maacldurka42: from within the source file it gives a nullpointer exception
08:57durka42you could catch the exception and run print-cause-trace on it
09:11Jomyooti know there isn't for loop
09:11Jomyootbut how would i efficiently emulate for loop. where i loop over 0..n
09:12Jomyootomg there is (loop)
09:12Chouserthe key question is why are you looping: producing side-effects? producing and returning a lazy seq? producing and returning some other kind of collection?
09:13Chouser,(for [i (range 10)] (+ i i))
09:13clojurebot(0 2 4 6 8 10 12 14 16 18)
09:13Jomyootproducing side effect
09:13Jomyootinserting into database
09:13ChrisPS,(repeat 7)
09:13clojurebotEval-in-box threw an exception:java.lang.OutOfMemoryError: Java heap space
09:13Jomyootwhere I need to change index value from 0 to n
09:13ChrisPSok
09:13Chouserok, so you probably want doseq
09:14Chouser(doseq [i (range 10)] (insert-into-db i))
09:14Chouserthat'll return nil after callking insert-into-db 10 times
09:15Chouseractually, dotimes is even better
09:15Chouser(dotimes [i 3] (prn i))
09:15Chouser,(dotimes [i 3] (prn i))
09:15clojurebot0 1 2
09:17Jomyoot,(range 20)
09:17clojurebot(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)
09:18Jomyootis there sin for using (for)?
09:19ChouserJomyoot: nope, 'for' is good. But it's lazy, which means if you're producing side-effects you can't be sure when (or if) they will ever actually happen.
09:20Jomyooti have to read into laziness
09:24Chouser,(do (for [x [1 2 3]] (prn x)) "all done?")
09:24clojurebot"all done?"
09:25Chousernote the numbers never got printed. So it's best not to use 'for' if you want side effects. Instead use doseq (or dotimes, or loop/recur, etc.)
09:25Chouser,(do (doseq [x [1 2 3]] (prn x)) "all done?")
09:25clojurebot"all done?"
09:25clojurebot1 2 3
09:25jdz,(do (prn "foo") "done")
09:25clojurebot"done"
09:25clojurebot"foo"
09:25Chouserheh
09:27jdzclojurebot should prefix the lines depending on what kind of output it is (standard output/error, return value)
09:27jdzi'm not volunteering ;0
09:28jdzalthough i imagine the change would not be complicated
09:59artagnonDifferent CL implementations on different platforms have different strengths and weaknesses. Why tie Clojure down to an implementation?
10:00ChousukeWhat do you mean?
10:00jdzartagnon: there's clojure-clr, did you know?
10:00clojurebot"[Clojure ...] feels like a general-purpose language beamed back from the near future."
10:00artagnonThere are tons of Scheme implmentations too. Gambit compiles directly to C and can be really really quick. PLT is the most widely used flavor of Scheme- it's excellent for beginners.
10:00jdzartagnon: anyway, what's your point?
10:01jdzartagnon: considering that Clojure is mainly a one-man project, and very young?
10:01Chousukeartagnon: The "official" clojure is "tied" to the JVM platform because that gives a multitude of benefits.
10:02artagnonjdz: I don't have a point. I'm asking the reason for the design decision
10:02Chousukeartagnon: nothing is going to stop you from implementing a flavour of Clojure for other host platforms though, but they will likely be incompatible, at least if host interop is used.
10:02Chousuke~rationale
10:02clojurebotrationale is http://clojure.org/rationale
10:02ChouserEarly Clojure supported both JVM and CLR
10:03ChousukeI suppose perhaps in the future there might be a Clojure specification, if someone bothers to write one.
10:03Chousukebut I think being implementation-defined allows Clojure to progress faster, which is important.
10:04ChouserI think the two main factors that caused the CLR support to be dropped were (a) the design of Clojure is not complete, and (b) one mature implementation is better than 2 immature implementations
10:04artagnonhm. So there's no specification draft? Just a couple of implementations to date.
10:04artagnonChouser: I see.
10:04Chousukeartagnon: yes. The JVM Clojure implementation defines Clojure.
10:05Chouserthere is one implementation, and it's structure and design is still evolving, though several of the key core concepts are quite stable and unlikely to change.
10:05ChousukeThere are also plans to rewrite the Clojure compiler in Clojure, which ought to make Clojure more "portable"
10:05Chouserthen there are a couple incomplete ports trying to follow along
10:06carkat the end of the day, the one implementation does the job, and we finally get to use a lisp in real life
10:06artagnonWhat's the current Clojure currently written in? Java?
10:06Chouserartagnon: yes, mostly Java plus some Clojure
10:06Chouserartagnon: http://blog.n01se.net/?p=41
10:07ChousukeIn addition to that, the core libraries use some java interop
10:07cemerickI've never quite understood the desire to have a specification -- seems like that's a great way to cast a language in amber, but exactly what you don't want to foster progress/innovation *shrug*
10:08artagnonClojure-in-Clojure is fine, but you need a Lisp environment first to eval those sexps.
10:08Chousercemerick: I agree.
10:08Chouserartagnon: yep! And we have one that's nearly good enough
10:08artagnonChouser: we do?
10:08carkartagnon : you only need those primitive forms
10:09artagnoncark: ofcourse.
10:09artagnonto be able to understand the Clojure that defines the rest of Clojure.
10:09carkas opposed to all the data structures and "standard library"
10:09artagnonLike the inbuilts in Elisp (written in C)
10:09ChouserIn a closed-source world, a language spec is fine -- necessary, I suppose. But I'm entirely content to have a single open-source implementation instead.
10:10Chouserartagnon: Clojure as it stands is nearly good enough to write Clojure-in-clojure well.
10:10RaynesWhat would be the best way to make a sequence of the result of 5 read-line calls without typing (read-line) 5 times?
10:10jdzinstead of writing language specification i'd rather like to see conformance tests being written
10:10artagnonRaynes: write a macro that unfolds the read-line 5 times?
10:10ChouserRaynes: (take 5 (repeatedly #(read-line x)))
10:11Chousukebeware: lazy seq :)
10:11ChouserRaynes: (vec (take 5 (repeatedly #(read-line x))))
10:11Chouser:-)
10:11RaynesThanks. :D
10:12artagnonDo equivalent Java programs perform worse? ie. I'm asking if we have an efficient compiler (the Clojure bytecode compiler ie.)
10:13Chouserthe byte-code produced by Clojure is efficient
10:13carkwell to be honest clojure is slower
10:14ChousukeClojure is typically slower than java, if you pay no attention your tight loops
10:14artagnonI see.
10:14carkboxing of primitive values, and function call semantics
10:14Chouserbut that doesn't have to do with the bytecode produced by the compiler
10:14carkbut inside a function you can get as fast as java
10:14ChousukeI mean, (reduce + (range 100000)) will not beat the equivalent java loop, but it's a lot easier to write :P
10:14artagnonChouser: Then what does it have to do with?
10:15artagnonChousuke: Why? What's the reason behind this?
10:15jdzChousuke: and better yet, (reduce + (range 1000000000000))
10:15Chousukeartagnon: well, + is a function.
10:15carkartagnon : and range produces a lazy sequence
10:15carkthat's overhead for convenience tradeoff
10:16artagnonAh, I see.
10:16carkstill you have the choice to make it as fast as java, by doing the same ugly thing as java
10:16rhickeyClojure calls to methods are precisely the same bytecode as Java's, so there's no general truth to 'Clojure is slower than Java'. Clojure's primitive numerics are also as fast as Java's. But, Clojure uses (Java's) boxed numbers by default and (Java's) boxed numbers are slower than (Java's) primitives.
10:17Chouserthe biggest common speed hit is when the code provides insufficient type hints such that reflection is done at runtime. This is very convenient for the programmer, but huge slowdown
10:17scgilardialong the lines of readline before, this works for me: (take 5 (repeatedly read-line)) (I don't see read-line taking an arg)
10:17carkrhickey : well calling a clojure function from clojure is slower than java, and primitives are always boxed on function boundaries
10:17rhickeycark: actually fewer ugly things, as CLojure infers much more given fewer hints
10:17carkagreed
10:18carkhey i'm sold on clojure ! just trying to be honest =)
10:18artagnonAnother thing I'd like to adress here: Many people hate Java. One of the reasons is that it's this whole shebang dump of this isolated box: Java has its own database (some JDBC or some such rubbish), graphical toolkit (Swig, right?) and other things.
10:19Chousukeartagnon: JDBC is just an API for accessing databases, not a database in itself. And the graphical toolkit is Swing. But there are also Qt bindings for java if you'd like to use that instead :)
10:19artagnonChouser: Right, I suppose there are some optimization features that trade off convinience for speed to use in specific bottlenecks in Clojure.
10:19rhickeywell, it's the generalities that are the problem. We can talk about anything specific, but people read those general statements and learn nothing about the truth of how to make things fast and what are the bottleneck. For instance, many have concluded that calling is slowing when it was primitive arg boxing holding things up
10:20rhickeySo tight-loop benchmarks that pass primitives as args suffer, but many others don't at all
10:20artagnonrhickey: so the slowdown has to do with the language's design (relying on boxed types for example) and not the design of the bytecode compiler itself.
10:21artagnonChousuke: Frankly, I was unaware. Sorry, I never really bothered to learn any Java.
10:21rhickeyartagnon: the JVM bytecode is so simple, and most optimizations are actually performed by HotSpot, so Clojure gets them
10:21rhickeyfree
10:21artagnonah, I see.
10:22rhickeyIt is a JVM limitation that one can't write fixnums as would be common in a dynamic lang
10:22Chousukeartagnon: well, I haven't bothered much with Java either. But Clojure is fun, and it helps to know the java libraries if you work with Clojure :)
10:22rhickeynot a language design issue - if there were unboxed fixnums in the JVM Clojure would use them
10:23artagnonChousuke: Right :)
10:23rhickeyThe JVM won't let a single type hold either a reference or a non-heap entity
10:23Chouserartagnon: the Java insular universe is actually related to my biggest annoyances with Clojure. But then again, the engineering work that has gone into that Java universe (JVM performance, library availability, etc.) is one of the things I like the most.
10:23ChousukeIs it possible to add fixnum support to the JVM without breaking backwards compatibility? :/
10:23artagnonrhickey: So it's more about the JVM not being tailor-made for Clojure.
10:24rhickeyartagnon: fixnums could be used by any dynamic lang on the JVM
10:24rhickeyhttp://blogs.sun.com/jrose/entry/fixnums_in_the_vm
10:24carki think there's a push for better dynamic language support on the jvm ... we might see some progress
10:24artagnonChousuke: Hey, nobody has actually explained this to me: But why is Java so isolated from the rest of the world?
10:24Chousukeartagnon: fortunately, there seems to be a lot of work going into making the JVM better for dynamic languages lately. :)
10:25artagnonrhickey: anything else apart from the fixnums that would help?
10:25Chousukeartagnon: Hmm. I don't think it's any more isolated than other languages utilising virtual machines.
10:25rhickeyartagnon: tail call optimization
10:25carkartagnon : not any more isolated than CL
10:25artagnonrhickey: It doesn't have tail call optimization!?
10:25rhickeyartagnon: nope
10:26artagnoncark: I thought CL was isolated because it's difficult and generally unpopular, no other reason :p
10:26ChousukeI actually prefer recur over true tail calls. it throws an exception if I get it wrong :P
10:26artagnonhm, that's terrible. SBCL has nice tail call optimization.
10:26artagnonChousuke: ofcourse, that's for testing.
10:27artagnonIn production, I'd let SBCL optimize it.
10:27Chousukeartagnon: no, I mean the recur special form in clojure, which is a workaround for the lack of TCO :)
10:27artagnoner, sorry. I'm unaware of this form.
10:27rhickeyartagnon: that's not the same at all - real TCO is a promise to eliminate, not an optional optimization. Only with the former can you design programs using calls as control flow without worrying about the stack
10:28carklack of TCO kept me away from clojure for a long time, than i tried it anyways, and i'm very glad i did =)
10:28rhickeyI'm talking about Scheme-style TCO
10:29Chousukeartagnon: basically, if you have a tail-recursive function you'd call like (foo x y), instead of having (foo x y) in the tail position in the definition, you just have (recur x y)
10:29carkwe have recur and trampolines to make it up, so that's really a non issue
10:29Chousukeartagnon: it can't do mutual recursion though. For that, you need a trampoline :/
10:29artagnonChousuke: oh I see!
10:29artagnonthat's interesting though.
10:30carkartagnon : are you thinking about giving clojure a try ?
10:30Chousukeit's not as elegant as it would be if the JVM promised TCO, but it's not too bad.
10:30Chousercark: and lazy seqs
10:30artagnoncark: ofcourse!
10:30carkchouser : ah yes indeed
10:31artagnonI'm just downloading it and setting up Emacs :)
10:31Chousukeartagnon: clojure-mode can do that for you, with clojure-install
10:31carkartagnon : great =) you'll find plenty of help in this channel to get you started (i abused it quite a bunch)
10:31Chousukeartagnon: also, http://java.ociweb.com/mark/clojure/
10:32artagnonChousuke: clojure-install doesn't work anymore :(
10:32Chousukeoh? :(
10:32artagnonChousuke: the git repo mentioned in the code is gone
10:32artagnonI'll tell you which line, wait
10:32Chousukehmm
10:32Chousukemaybe you have some old version of clojure-mode?
10:33artagnonI got it from jochu's GitHub head.
10:33artagnonand besides, I don't like auto-things anyway. Especially not auto-installing things. They freak me out a bit :p
10:33Chousukehmm, yeah, that seems to be a bit outdated
10:34Chousukehttp://github.com/technomancy/clojure-mode/tree/master this fork of it is a bit better maintained :)
10:34artagnonI want to be able to switch swank backends. I'm not going to stop writing CL or anything :p
10:34Chousukeheh
10:34artagnonChousuke: ah, thanks! :)
10:38Chousukerhickey: how's the chunks branch coming along, btw?
10:39rhickeyChousuke: I'd like to see some contribs for chunked for/take/drop etc
10:39cemerickheh, and I was going to ask about new-new. :-P
10:41Chouserc-in-c could be written today: reader and compiler are blocking on nothing and the data structures could use proxy.
10:41rhickeycemerick: newnew touches deeply on what I want Clojure to be. I'd be pretty happy to have it not have most of genclass, and have people always have to define interfaces
10:41rhickeyI really don't want to embed Java in Clojure
10:41Chouserthis would create a slower-clojure-in-clojure that may be a more pleasant language in which to write new-new?
10:43rhickeyChouser: not sure about that question - it would be as fast as Java, but not support some things, e.g. mutable fields
10:43cemerickrhickey: that's 95% of what I want, and the other 5% I can proxy.
10:44Chousercemerick: when would you use proxy?
10:44rhickeycemerick: proxy with proxy?
10:44rhickeyor did you mean stub somehow?
10:44cemerickThere are times when one needs to produce a subclass, etc.
10:45cemerickrhickey: Maybe new-new would support that as well, but there's no telling, esp. the way you talk about interfaces.
10:45rhickeycemerick: so, subclasses are a key consideration right now. In fresh designs, I'm not in favor, but 2 things mitigate: many Java libs require concrete derivation, and: Clojure's impl makes use of abstract classes
10:46cemerickI remember your first shot at proxy (maybe a year ago, named differently) only worked with interfaces.
10:46rhickeyIt's about defining names classes more than deriving
10:47cemerickI think not being able to subclass would be a significant blow to interop and adoption. proxy would have to stick around in some form.
10:47rhickeyso if you can derive from and abstract class, but not create one...
10:48rhickeyI'm really concentrating on the cinc story - how to move the data structures over, what to do with the abstract bases - define a better way to do reuse-via-composition?
10:49rhickeyor, a genclass variant with the same direct-call code gen as newnew?
10:50artagnonIs there a plan to port the Clojure compiler to say, LLVM? Would it serve any purpose?
10:50cemerickwell, it seems that avoiding the indirection is critical for performance, so I'd assume anything genclass-esque is out
10:50rhickeynewnew really needs fn + proxy, but half that code is in Java and the other half is in Clojure
10:51rhickeycemerick: there's no reason there couldn't be a genclass variant that had the method bodies inline
10:51cemerickwell, in that case :-)
10:52rhickeyartagnon: where are the libraries for LLVM?
10:53artagnonOh right. Not only would you have to re-invent things like GC, but all the Java libraries that you took for granted too ~!
10:54Chouserrhickey: so it would be actually beneficial to have today's compiler feature set implemented in Clojure? Or am I reading too much into that.
10:55cemerickrhickey: couldn't an abstract base instance just be another field in the subclass object? supermethods would be directly callable...
10:55artagnonIt took some time for me to grasp the fact that the JVM is so generic that it should be called HLVM instead.
10:56Chouserartagnon: or maybe OOVM
10:56rhickeyChouser: I think you may be reading into that, I'm still thinking about what it needs to do, not how to do it, other than it looking like a lot of work, either way it is done
10:56artagnonChouser: it's object-oriented?
10:56artagnonwhat does OO have to do with it?
10:58Chouserartagnon: yes, as far as I know object, methods, inheritence, etc. are baked pretty deeply into both the JVM bytecode spec and the implementation(s).
10:58rhickeycemerick: It's about this - what's the recipe for writing Clojure in Clojure, especially the data structures? Does one rewrite the interfaces using gen-interface and write the impls using newnew? That leaves a hole around the abstract classes
10:58artagnonI see. I haven't looked into that at all actually.
10:59rhickeythere are also a very few cases where even one other object creation impacts perf in a way that matters
11:00rhickeyany composition strategy has issues there
11:00artagnonAnother (probably very stupid) question: What kind of an environment does say, SBCL provide? It's very Lisp-specific and doesn't have the unnecessary features of the JVM. Does it lack something?
11:02rhickeyChouser: I have looked at the compiler stuff you've started - I guess I'm loathe to do a rewrite and not improve things. As I've said before, I wouldn't use dynamic binding similarly again, would pass environments explicitly, also the reflection is woven throughout and the use of class instances might be better with names
11:04Chouseryeah, the code I have tries to improve things it shouldn't ("instance" instead of fn) and fails to improve things it should (set! side effects all over the place)
11:04rhickeyartagnon: any CL has only a tiny fraction of the libraries of Java, and also a tiny fraction of the users of those libraries, thus less testing etc
11:05cemerickrhickey: I guess I'd say that one should be able to produce abstract classes with newnew as well (though calling them that is a little odd -- they'd just be usages of newnew that don't have impls for all methods). The subclasses can refer to them by var-name, which (at least in my head) would allow you to pick up what the actual generated base classname is at runtime, and declare that base class as the superclass.
11:05rhickeyChouser: I understand the strategy of 'copy the Java into Clojure' in order to move forward in CLojure, might mean writing the compiler twice
11:05cemerickDoing anything else would seem to require developing a parallel object system or some other approach.
11:05scgilardiartagnon: and amazing toos for profiling, visibility into the workings of the VM
11:06scgilarditools
11:06rhickeycemerick: that kind of dynamic use of class names is a definite no go. Java class names are static and I'm not going to pretend anymore, it's a disaster for OSGi and other modularity systems
11:07Chouserrhickey: that was the only strategy I could follow without understanding the inner workings of the current compiler better. except for the poorly-chosen attept to implement "instance".
11:07artagnonrhickey: Right. Got it.
11:07danlarkinartagnon: SBCL doesn't use a VM (as far as I know, at least). It does native code generation
11:08cemerickrhickey: Sounds fine by me. In that case, (new my.class.name [bases] [s-args] ...)?
11:08rhickeycemerick: in line with that, I think we need a distinct static phase of compilation, for interface defs at least
11:08rhickeycemerick: my.class.name is defined where?
11:08artagnondanlarkin: at all? Are you sure? I never thought stuff like hotpatching would be possible without a VM.
11:09cemerickrhickey: that's a symbol that controls the name of the class generated by the compiler when it loads the newnew form
11:09rhickeycemerick: for use by what other code?
11:10rhickeythat's the fundamental problem, you can't dynamically define named JAva classes without a ton of problems, with classloaders, redefinition etc
11:10cemerickin the context of cinc, other newnew usages that define concrete impls (new c.l.SomePersistentDS [my.class.name other-interface] ...)
11:11Chousercounld abstract base classes be replaced by a sort of mix-in idea? new-new could generate classes that provide implementation from some other place when not specified in the form.
11:11cemerickthat's mostly what I'm getting at, without having the benefit of intimate knowledge of the bytecode involved :-)
11:11Chouserwould be a pain for Java code trying to re-use the abstract "class", but who wants to write java?
11:12rhickeyChouser: yes, exactly, that's the kind of thing I'm thinking about
11:12artagnonThanks for everything, all. I'll give Clojure a spin.
11:13rhickeyChouser, cemerick: if not composition, then we're talking about some sort of mixin/macro thing
11:13clojurebotWho??
11:14rhickeymight be as simple as - use these defs if no others are provided
11:14cemerickthat makes super somewhat more difficult, no?
11:14rhickeyI could probably have done most of the data structures that way
11:15cemerickrhickey: this is where my lack of understanding of the details kills me. If there's only one "mixin", isn't that just an abstract class?
11:15rhickeycemerick: super wasn't that important for me, it's almost always a bad sign
11:16cemerickrhickey: critical (super-critical!) for interop, though. If you're going to care about things like osgi, then you've got to have an abstract class extension story.
11:17rhickeythere are only 5 super uses (that aren;t ctor calls) in clojure.lang, 3 are forced on my by Java bases classes
11:19rhickeycemerick: we're are talking about replacing the abstract bases in clojure.lang, that's a separate question from being able to derive from abstract bases. Even if the latter is possible, doesn't mean we want to have to define abstract bases in clojure
11:19rhickeyconsuming vs producing
11:20rhickeyin all likelihood newnew will retain proxy's ability to derive from concrete classes, and improve the super access story
11:20rhickeybut that's not the same as providing tools for defining abstract classes (other than existing genclass)
11:21rhickeyi.e. if newnew is the only way to define the highest-performing classes, how do you replace abstract bases in your Clojure designs?
11:21rhickeygiven newnew defines an anonymous class
11:22cemerickrhickey: well, see, I underestimated your ambitions again :-)
11:24cemerickrhickey: FWIW, I think traits are the best thing about Scala. Clojure could do worse than be influenced by them.
11:24rhickeya concrete code reuse mechanism other than inheritance is a promising idea, gets out of naming and dynamic redefinition troubles
11:24Chouseryou could still do super with mixins if you want to
11:25RaynesTraits are nice.
11:25cemerickobviously a lot of "stuff" there related to the type system, but the general model and workflow is nice.
11:25rhickeythe dynamism is the trick, these things can't become names Java classes
11:25rhickeynamed
11:25cemerickChouser: agreed.
11:25rhickeycuper is bad design
11:26rhickeysuper
11:26cemerickrhickey: neither are scala traits, actually. They produce an interface of the same name as the trait, though (along with some generated name that scalac picks up).
11:26Chouserthe set of fns to define the abstract base should be static things anyway, right? so a special form ... well, ok. We don't have to support it, but nothing about the broad design for mixins as described prevents them from working.
11:27Chouserhm, actually, I make kind of mixin macro for proxy recently.
11:27Chousermade
11:30ChouserI guess I mentioned it before -- allowed me to define a new anonymous class that inherited from APersistentMap, mixed in some calls to a delegate instance of PersistentHashMap, and then provide implementations for methods from another interface.
11:30Chousernew anonymous class via proxy
11:31Chouserso, um, it worked fine. :-)
11:32rhickeydynamic anonymous is fine, dynamic named (class or interface) is the problem
11:33Chouserright. so these mixins would be named and therefore not be a class or interface
11:33rhickeyso the code we want to reuse has to be either a) staitc (e.g. genclass) or b)unnamed (e.g. not named by class/interface name)
11:36rhickeyWhat's interesting about all of the abstract bases in Clojure is that there is/are corresponding interface(s) (as there should be)
11:41rhickeyso if a newnew instance, acting as a prototype for an abstract base, sitting in some var, had an accessible (though anonymous) name (as suggested by cemerick earlier), then a 'mixing' newnew class could just declare it implements the same interfaces. Constructors are a problem though
11:42rhickeynewnew hides ctors
11:43Chouserthe mixing class's undefined methods would call methods of the mixed instance? wouldn't the mixing instance have to be passed in somehow?
11:43cemerickthere's still one under the covers, though. The mixing class just provides super-args that align with those defined by the referenced newnew instance...?
11:44cemerickChouser: implicit first 'this' arg?
11:45Chousercemerick: but that would be a different method signature than defined by the interface its supposedly implementing!
11:47cemerickI really do mean *implicit* -- you'd use the 'this' symbol in the method impl, but the compiler would have to drop in the reference to the callee.
11:47ChouserI was assuming a mixed thing would have to be something like a class full of static methods whose names and signatures were similar (but not identical) to the instance methods defined by an interface.
11:48cemerickI don't think the resulting newnew concrete instance would be usable from a Java interface standpoint in that case.
11:49cemerick(not without a proxy object in front setting up the calls properly)
11:49Chousercemerick: but drop that reference in where? if the method signature is defined by a public named interface, how do you pass in anything other than the "template" instance for the mixed class?
11:50yasonQ: is there byte-seq that is analogous to line-seq ?
11:50Chouseryes, it would be a pain to try to use mixable class from java code
11:51cemerickmy understanding is that the "template" instance wouldn't be used at all -- only its anonymous yet named class, with method impls, would be used.
11:51cemerickThe template instance is just a handle that allows newnew to get a hold of the abstract base/mixin class.
11:51cemerick(at least how I'm reading rhickey's last msg)
11:52Chousukeurgh, for is a complex beast :P
11:52cemerickyason: how would such a thing segment the byte stream?
11:53Chouserahh... so when given a mixable, newnew would ... copy the method implementations directly into the mixing class def?
11:53rhickeyChouser: the point I was trying to make about interfaces was that if the mixing-in class only fulfills the same contract as implied by the interfaces shared with the mixin, then the mixin can make blind calls to those methods, knowing they will call the most-derived versions
11:53Chouseroh!
11:54rhickeythis is the non-macro-like solution, a macro-like one would eschew inheritance completely, just insert code when needed. There, as I said, I think calling super is bad and unnecessary
11:54yasoncemerick: what do you mean?
11:55cemerickyason: line-seq breaks up text by line breaks -- how would you want to break up your InputStream?
11:55yasoncemerick: I'm thinking of a lazy sequence of bytes read off from some reader
11:55cemerickor, InputStream's bytes
11:56Chouserso a mixing newnew class would actually inherit from the anonymous class of the mixable newnew?
11:56rhickeyChouser: right
11:57rhickeythe tricks are: making newnew generate an abstract class when needed, constructors
11:57rhickeya newnew class gets a ctor, (as does a fn) that takes as args all closed-over locals, but Clojure completely hides that
11:58cemerickrhickey: and my point about ctors is that, the mixable class has ctors (or factory fn, whatever), and the mixing class can just pass super-args as one would with proxy today
11:58rhickeywere the newnew class be used as a base, there's have to be some access to that ctor
11:59rhickeycemerick: factory fn is not a ctor, can't be used to init a base
11:59rhickeyexposing the implicit ctor gets icky quickly
11:59cemerickright, right
12:00cemerickhow so?
12:01rhickeybecause some aspects of the mixin prototype would have to be 'free' names
12:01Chouserthe fields for closed-over values could be mutated once during creation. just mark them final but change them once anyway.
12:02rhickeye.g. (def x (let [a 42 b 57] (newnew [Object] [] ...))
12:03rhickeya and b will be args to the class iff they were used in the impl, as would any other closed over things, might not be one level. No way to say, I want a to always be 42 and b to be a variable thing supplied by derivee
12:04rhickeyChouser: that abuse of final is in conflict with the optimizer - you might not see that new value in all threads
12:05Chouserrhickey: already ducked.
12:05rhickeyjust saying, it's not an option even
12:06cemerickChouser: I already made rhickey blush talking about mutable fields a week or two ago ;-)
12:07rhickeymutable fields unlikely too, the only arg for them is the multiple allocation cost for something like AtomicReference or clojure.lang.Box
12:08rhickeybut the lowest-level Java code of Clojure does use mutable fields, with all needed precautions synchronization-wise
12:09Chouserto specify mutable fields you'd have to give up some of the beautiful simplicity of closing over a regular local for all your state.
12:09cemerickrhickey: not so. I want to stop having to think about massive intermediate garbage produced while (for example) reducing a struct through transformation. Right now, in order to avoid that, I need to manually pull out the fields of interest and loop through them, and then create a struct at the end using the transformed values.
12:10cemerickthat said, I'm certainly not expecting there to ever be a path provided for that sort of thing in clojure.
12:10rhickeycemerick: heh, I just designed one yesterday
12:10cemerickoh?
12:11rhickeybatch updatable persistent data structures with O(1) conversion to/from mutability
12:11rhickeya.k.a. the holy grail
12:12rhickeynot a joke, I've been working on the vector all day yesterday and during this discussion today
12:12cemerickvector?
12:12cemericknah, I'm getting punk'd.
12:13rhickeyyes, PersistentVector replacement
12:14Chouseronly abstract newnews would need constructor args, right?
12:14rhickeyyou can say (let [v! (mutable v)] ...) and get a non-sharable vector supporting conj!, nth!, pop!, when you are done call (immutable v!), both mutable and immutable are constant-time
12:14cemerickI'm lured in. If that's true, then that can be newnew's fields AFAIC
12:15rhickeyChouser: all newnews that close over have ctors, it's a matter of exposure, usually the enclosing factory fn calls the ctor implicitly
12:15cemerickrhickey: assoc as well?
12:15cemerickassoc!, perhaps?
12:15rhickeycemerick: yes assoc!
12:16rhickeythe general design will apply to all of the data structures except lists
12:16dysingerinteresting
12:16Chouserrhickey: right, I mean only abstract newnews would need to be able to expose ctor args so that a derived class could pass them in explicitly.
12:16rhickeyChouser: right
12:16Chousukerhickey: non-sharable meaning what? is it allowed to leave the scope it's created in? :)
12:17rhickeyChousuke: meaning, if you share copies of it you are in trouble and I can't help you
12:18rhickeybut the updating is open in general, and after an immutable call I can help you, preventing any further mutation
12:18Chouserso an abstract newnew would list formal ctor args (that would actually be added to the full list of args for closed-over things) and a concrete newnew would list actual values to be passed in to the base class.
12:19Chouserhm, I guess an abstract base class may itself want to derive from another abstract and be able to pass in ctor values.
12:19rhickeyChouser: yes, it gets ugly
12:19rhickeyI'm not sure bending newnew to do this is the right thing
12:20rhickeyChousuke: the prototypical 'right' use case is something like into, or other birthing situations, where no one will see the interim values
12:20ChouserWould you guess that abstract bases will only rarely want to close over locals?
12:21rhickeyChouser: I was going to say that before, but I'm not sure - it's the nice way to build in constants
12:22Chouserbecause of course as soon as you're closing over things, you want something very much like newnew
12:22rhickeyChouser: exactly
12:25ChouserI really like the kind of dynamism this would allow. redef the base newnew and you actually get a new anon class, so all existing derived instances continue to behave as they had. But new derived instances will see the new base class and pick up the new behavior.
12:26rhickeyChouser: yes, I'd love to keep the static-ness to interfaces, which are still critical
12:27rhickeyChouser: another sticking point is that newnews would normally only have one ctor, many abstract bases have multiple ctors
12:30Chouserew
12:31cemerickis that at all necessary for cinc?
12:45beutdeucei'm getting an unquote is unbound illegalstateexception. What does that mean?
12:46Chouserit means you're using ~ outside of a `
12:46beutdeucehow do i epxress inequality?
12:46beutdeuceexpress*
12:46Chouser,(not= 2 3)
12:46clojurebottrue
12:46beutdeucek, thnx
12:50beutdeuceany idea why i'm getting a stack overflow? => http://pastie.org/548306
12:53cemerickvery strange here: I've got a slot with the value: (delay (apply merge (pmap expensive-map-producing-fn [somedata]))) When I use pmap, the resulting delay contains an *empty map*. When I use map, I get correct results.
12:54cemerickbeutdeuce: you're calling length recursively
12:54beutdeucecemerick: it should stop when there is no more xs
12:55maaclbeutdeuce: you are checking against nil
12:55maacl(= nil "")
12:55maacl,(= nil "")
12:55clojurebotfalse
12:56beutdeucewhat does the , mean?
12:56maaclbeutdeuce: it asks clojurebot to evaluate
12:56beutdeuceah, cool
12:58beutdeuceno, i need to check if xs is not equal to zero
12:58beutdeucewhich is not=
12:58beutdeucebut for some reason, it never equals zero, which it should
13:02technomancybeutdeuce: the empty list is not nil in clojure
13:02technomancy,(nil? ())
13:02clojurebotfalse
13:02technomancy,(empty? ())
13:02clojurebottrue
13:02beutdeuceah
13:02beutdeuceempty?
13:02technomancybeutdeuce: that's what you want instead
13:03beutdeuceajd to check if it isnt empty?
13:03beutdeuceand*
13:03cemerick,(seq '(1 2))
13:03clojurebot(1 2)
13:03cemerick,(boolean (seq '(1 2)))
13:03clojurebottrue
13:03cemerick,(not (empty? '(1 2)))
13:03clojurebottrue
13:04beutdeuceis there a ! in clojure to signify not?
13:05technomancybeutdeuce: ! has different connotations in clojure; it usually signifies side-effects
13:05beutdeucei see
13:05technomancynot is just not
13:06beutdeucek
13:10rhickeyhttp://java.sun.com/javaone/2009/rockstars.jsp
13:12technomancyrhickey: nicely done.
13:12rhickeyit's good for Clojure to get on the radar in such a mainstream venue
13:13hiredmanrockstars? you'll need to beadazzle your jeans
13:13technomancy\m/
13:16technomancyso what's the deal with this guy who's doing his own (non-clojureCLR) C# port of Clojure? http://code.google.com/p/ajlisp/updates/list
13:23beutdeucelol, now i get a null pointer
13:26Chouserthats a whole lot of rockstars.
13:30Chouserdoes the JVM disallow operations in ctor before calls to super's ctor? Or is that a Java-level thing?
13:33liebkerhickey: I was just reading your JavaOne slides (linked on the rock stars page), do you have a copy of them on a public server that I can point people to (without registering with the SDN)?
13:34rhickeytechnomancy: I really wish he wouldn't call that Clojure
13:34rhickeyI also pointed him to Clojure CLR, but he's persisted
13:34ChouserYou asked him to stop using the name and he's refusing?
13:35rhickeyNo, I haven't asked him to stop yet, will do
13:35technomancyI hate that I'm saying this, but it might be wise to register the trademark if you haven't. =\
13:36rhickeytechnomancy: yes, I've been looking at what Python does with theirs, seems sensible
13:37rhickeythere are some issues with trademarks and some distros, no?
13:38technomancyyes, but IIRC only trademarked artwork
13:38rhickeyunfortunately just more work and expense for me
13:38technomancyit's a shame that it's necessary
13:38technomancythe free software community has a great legal framework for dealing with copyright, but nobody has really got anything satisfying for trademarks
13:39Chouserit may not be necessary. his project is more likely to get long-term traction under its own name than if its generally known as a bad-will knock-off.
13:44technomancypython's guidelines seem pretty sane
13:45Lau_of_DKrhickey: Alternatively if you want to navigate around a potential legal battle, you could rename Clojure to .. oh I dont know.. Clabango? :)
13:46danlarkin*rimshot*
13:47cemerickThe Clojure Foundation is not far away, I guess.
13:47Chouserbleh
13:49Chouserbudgets board meetings elections lawyers
13:49beutdeuce_technomancy: ruby's are even more :)
13:50cemerickChouser: the ways of the world
13:50clojurebotWhy are you asking *him*
13:50Lau_of_DKhehe
13:50Lau_of_DKnasty bot
13:53beutdeuce_how would one go about creating custom types/type classes in clojure?
13:55Chouserbeutdeuce_: most of the time it's best to just provide a bunch of functions that operate on a map or vector of a particular shape
13:56beutdeuce_Chouser: i see, so clojure takes a different approach than haskell.
13:57dnolenbeatdeuce_: if you need something complex/fancy look at multimethods, add-hoc hierarchies, and metadata.
13:58Chouserand if you need to provide an interface that can be used by regular Java code, look at gen-interface and proxy
14:02cemerickthis map/pmap behaviour is *really* strange -- only manifests itself when the pmap call is made on the AWT event thread
14:20hiredmancemerick: please continue
14:21cemerickhiredman: not sure what else to say beyond what I've said already. I'm pretty baffled.
14:21hiredmanmust have missed the initial explanation
14:22cemerickvery strange here: I've got a slot with the value: (delay (apply merge (pmap expensive-map-producing-fn [somedata]))) When I use pmap, the resulting delay contains an *empty map*. When I use map, I get correct results
14:22hiredman~def delay
14:22hiredmaneep
14:22hiredmanthats not right
14:23hiredman~def clojure.lang.Delay
14:24hiredman~def pmap
14:30hiredmanhmmm
14:32hiredmanhave you tried just wrapping in a closure?
14:33cemerickhiredman: not yet, but I'll throw that dart at the wall next :-/
14:33hiredman:/
14:34cemerickDebugging facilities leave much to be desired. Thankfully, nearly all of our fns are small and functional enough that reasonable unit testing is straightforward and almost-uniformly successful.
14:42hiredman,(doc merge)
14:42clojurebot"([& maps]); Returns a map that consists of the rest of the maps conj-ed onto the first. If a key occurs in more than one map, the mapping from the latter (left-to-right) will be the mapping in the result."
14:43ataggartit would be neat to have a dummy stack be created during execution that holds the clojure line numebrs etc (like clojure.test's output). just for testing/.debugging of course.
14:44cemerickrhickey: did you say something before about how you'd like to have reified environments?
14:45Chouserthe java stack holds clojure line numbers
14:46ChousukeI guess macros complicate the line number stuff? :/
14:47ChouserI would think so. might even be hard to define what you'd want
14:47ChouserI suppose CL has addressed this
14:48cemerickhiredman: wrapping the pmap call (and the entire body of the delay) in a thunk had no effect
14:48cemericknor did eliminating the delay
14:48hiredmanweird
14:48hiredmanis your function creating non empty maps? :P
14:48ataggartwhat reason, other than caching, would one use delay/force vs quote/eval
14:49cemerickheh
14:49cemerickhiredman: note that the results are perfect over the same dataset if I change pmap -> map
14:49Chousukeataggart: why would you use quote/eval if delay/force works? :/
14:49hiredmanwell
14:49cemerickyou're saying I just *think* it's the same dataset? :-)
14:49ataggartpremature optimization :( I should know better, but...
14:49hiredmancemerick: I dunno
14:50hiredmanit seems like a good idea to check
14:50hiredmanput some logging in expensive-map-producing-fn
14:50cemerickyeah, I did that first, actually :-)
14:50hiredmanat it is producing the expected results
14:53cemerickas far as I can tell.
14:53cemerickI'm sure I'm the one screwing up, but it's convenient to think that might not be the case for a little while.
14:54lisppaste8ataggart pasted "logging functions (jul, log4j, commons)" at http://paste.lisp.org/display/83697
14:54ataggartif anyone thinks that's worth sticking contrib, be my guest
14:54ataggartmy CA is in the mail
15:13mebaran151ataggart, that actually looks really nifty
15:13ataggartthx
15:14ataggartneeds better documentation and examples tho
15:15ataggartI just didn't want to write an actual logging system, there's enough of those around
15:18cemerickataggart: yeah, that's pretty decent. Why bother with the separate commons-logging bit though, since you have separate support for log4j and java.util.logging?
15:23ataggartbecause commons-logging has its own config stuff, and some companies (like mine) use it
15:23ataggartmy approach was not to mess with whatever someone might have already been doing in their java code
15:24cemerickoh, I didn't realize c-l had much of any configuration available...it's been a long time since I've touched it
15:24ataggartalso cl supports other logging systems
15:24ataggarte.g. slfj
15:24ataggartwhic I didnt get around to adding
15:26ataggartI did really enjoy the fact tat it was way easier to check for the presence of a lib with clojure than what the cl folks had to do in java
15:27cemerickis slfj used much at all?
15:27cemerick(I've never seen it in the wild)
16:23ChouserI'd really like class name aliases
16:24ChouserI guess this case is bad enough a macro would help...
16:29cemerickhiredman: and the winner goes to.....pmap + binding!
16:30hiredmanhuh
16:30Chouseryep, that would do it
16:31rhickeycemerick: what's the contest?
16:31Chouserbinding is really quite pernicious in a thready, lazy, closury environment
16:31cemerickrhickey: I had a pmap call that was failing in a UI context, but not in a headless context, *and* it worked in the former if I switched to map.
16:32cemerickturns out I had a dosync floating around 50 stack frames up, so the threads used in the pmap couldn't see a variety of things.
16:32cemerick(only in the UI, that is)
16:33cemericksorry, s/dosync/binding
16:34maaclCan anybody give me some hints on how to translate this: http://bit.ly/lcs_py (the backTrackAll function) from Python into Clojure? I have a pasted my attempt here: http://paste.lisp.org/+1SL7, but it doesn't work. For completeness I have included the functions required to test the traceback-all-lcs function and my traceback-lcs function (that works :-)).
16:34cemerickalthough the same issue would pop up in a transaction where some lower level used pmap, or futures, etc.
16:35rhickeycemerick: when something is running in a thread pool as utilized by pmap, I don't control the thread
16:35rhickeyand it could be taking on work sent from multiple contexts
16:35Raynestechnomancy: Is this a known bug? http://tr.im/sGhH
16:35rhickeyso you really need a fn that captures any bindings you care about
16:35cemerickrhickey: yeah, I understand the dynamic, I had simply forgotten about the binding stuff that was going on in the UI
16:36rhickeyI think there should be some with-captured-bindings macro
16:36rhickeyyields a fn
16:37rhickeybut generally I think people have this weird expectation that closures should know if they are going to run in other threads and do something different
16:38cemerickwell, it's not so much that as a caller doesn't necessarily know what a fn is going to do w.r.t. parallelizing computation, and a fn can't always be sure of the environment it's going to be called in
16:40cemerickJust thinking about the pmap usages that I have floating around, I'm starting to get uneasy about the notion of using refs with (potentially) large transaction scopes for my cells reimpl.
16:40technomancyRaynes: not known by me, but I'm far from an expert on Windows
16:40rhickeyI don't disagree that that is in conflict with dynamic binding generally, but pmap is explicit
16:40rhickeyand pcalls, and future, and send
16:40Raynestechnomancy: Happens here on Ubuntu Hardy as well.
16:40RaynesApparently Brian Carper gets the same thing.
16:41Chouserdoes dosync use thread-local data?
16:41ChouserI suppose it must...
16:41cemerickrhickey: yeah, I'm just jabbering into the wind here. The tools are fine, I just need to apply them a little more consciously.
16:41cemerickyeah, transactions are thread-local until they've committed
16:41rhickeycemerick: not at all, I've been thinking about what would be a good alternative to dynamic binding for concurrent use
16:41technomancyRaynes: oh, right. I think the problem is actually that *in* is hooked up to the *inferior-lisp* buffer instead of the *slime-repl* buffer
16:42Raynes:o
16:43RaynesHow would I go about changing that >_>
16:43rhickeythere is a long-standing argument about inheritance of environments by sub-threads, but that is born of an old-styile use of manually launched threads. Thread pools ruin any notion of nesting or child thread
16:43cemerickrhickey: what would the options be in general, short of passing around environments between thread boundaries?
16:44cemericks/between/across
16:44technomancyRaynes: buffer interaction with slime doesn't fit well into the streams paradigm. I've only used read-line etc in conjunction with sockets from slime
16:44rhickeycemerick: closures would have to capture definition context of some sort
16:46rhickeynot normally what you want wrt dynamic vars, but perhaps explicitly
16:47rhickeyif an explicit construct could do that, and re-establish, it would cover all calls made by it. You would only need to do that in the fn you pass to pmap/agents etc
16:48rhickey(pmap #capture-this-env(foo %) xx)
16:49rhickeypeople really expect that of the anonymous fns they pass to pmap, but not in their defns
16:49rhickeyeven though they are the same
16:50hiredmanbasically a short cut for (binding [a 1] (let [a a] (fn [] (+ a 1))))
16:50hiredman?
16:50rhickeyhiredman: not, it has got to do a real rebinding, so nested calls see the dynamic vars
16:51hiredmanoh
16:51rhickeyso (let [a *a*] #(binding [*a* a] ...
16:51hiredmanyeah
16:51rhickeydefinitely macro-able
16:52rhickeythe only trick is you want args usually
16:53technomancyRaynes: it looks like swank-clojure doesn't rebind *in* at all
16:53rhickey(pmap (fn-with-bindings [*a* *b* *c*] [x] ...) xs)
16:53rhickeyfn-capturing
16:54rhickey(fn-capturing [vars] [args] body)
16:54rhickeyor something
16:54kotarak(defmacro bound-fn [vars args & body] (let [gens (take (count vars) (repeadetly gensym))] `(let ~(vec (interleave gens vars)) (fn ~args (binding ~(vec (interleave vars gens)) ~@body)))))
16:54rhickeyright
16:55cemerickhrm
16:55technomancyRaynes: doesn't quite do what you want, but it might be a start: (binding [*in* (java.io.BufferedReader. (:reader swank.core.connection/*current-connection*))] (read-line))
16:55rhickeycemerick: I understand you may not know what vars are used by nested calls
16:55cemerickyeah, that's one big issue
16:56rhickeythat is a separate problem, I might be able to make capturing all bindings cheap
16:56rhickeythe bindings system is designed to make that possible, or at least was
16:56rhickeycould still again, an implementation detail
16:56cemerickactually, that's the biggest issue, esp w.r.t. transactions. To do what I was thinking of doing, I'd need transactions to span multiple threads -- which, now that I've said it, doesn't seem like a good plan in general.
16:57kotarakmaybe fn-with-bindings could go into c.c.core until something suitable is ready?
16:58Chousukekotarak: you don't need the (take (count vars) ..) part actually.
16:58Chousukeinterleave stops when it runs out of items in one of the seqs :)
16:58kotarakah. Nice. Like map.
16:59rhickeycemerick: if those threads touch refs then you need help, if they just do computations then that's ok
17:00cemerickrhickey: so if they're doing computations on refs, they cancel each other out or something?
17:00cemerick;-)
17:00cemerickno, my current/former plan is just wrongheaded.
17:03cemerickfutures and pmap aren't really the "problem" -- it's not strictly necessary that I parallelize at that level of granularity. The real issue is using the cells impl in conjunction with a UI (where one will inevitably want to push some computation out to another thread).
17:10rhickeyalrighty - http://github.com/richhickey/clojure/commits/master
17:11rhickeyif someone would please implement push/pop/get-thread-bindings, this new (clojure.lang.Var/getThreadBindings) will get you a map ready to push
17:12rhickeythis will let you build the (preferable) capture-all-bindings
17:13rhickeyuser=> (clojure.lang.Var/getThreadBindings)
17:13rhickey{#'clojure.core/*command-line-args* nil, #'clojure.core/*print-meta* false, #<Var: --unnamed--> 2, #'clojure.core/*ns* #<Namespace user>, #'clojure.core/*math-context* nil, #<Var: --unnamed--> #<DynamicClassLoader clojure.lang.DynamicClassLoader@7e28388b>, #'clojure.core/*2 nil, #'clojure.core/*warn-on-reflection* false, #'clojure.core/*3 nil, #'clojure.core/*1 {#'clojure.core/*command-line-args* nil, #'clojure.core/*print-meta* false, #<
17:13cemerickhmm, fancy
17:14cemerickthe nice th
17:15kotarak(defmacro fn-with-bindings [args & body] `(let [bindings# (clojure.lang.Var/getThreadBindings)] (fn ~args (try (clojure.lang.Var/pushThreadBindings bindings#) ~@body (finally (clojure.lang.Var/popThreadBindings))))))
17:15kotarakand
17:16rhickeybinding* ?
17:16rhickeya finally without it's own try?
17:16kotarakA function doing what binding does accepting a map.
17:17rhickeytools are there to build that
17:17kotarakbinding could then look like `(binding* ~(construct map here) (fn [] ~@body))
17:17rhickeyI'd prefer not to have Var/blah - these can become proper supported fns push/pop/get-thread-bindings
17:17kotarakrhickey: I know. I did several times...
17:21kotarakrhickey: this is what I had in mind: http://paste.pocoo.org/show/129042
17:22kotarakBut it throws.... which means it's possible to inject something.
17:22rhickeykotarak: I don't get it, what's the point of my-try?
17:23rhickeyno user should be writing finally outside of try
17:23rhickeyI think it is a non problem
17:24kotarakI don't know whether it is problem or not (most likely not). But if I expand a macro into a try wrapping some body I could inject accidentally some catch clause.
17:24kotarakWhat users should do and what they actually do, are two different things... But I agree that this is not really a problem.
17:25rhickeykotarak: I don't see how unless people are writing loose finally/catch clauses, else they would nest
17:26rhickeyanyway, with getThreadBindings you can now have some fun
17:26kotarak(my-macro-expand-in-a-try (try (my-user-try)) (catch SomeException ...)) One wrong paren later.... but anyway. It is not a problem. Otherwise it would have already been mentioned...
17:34Chouserrhickey: has your interest in a finger-tree diminished with the vector stuff you were describing today?
17:34clojurebotrhickey is a T-1000 sent from the future
17:58rhickeyChouser: not at all, finger-trees will support fast insertion in the middle and concatenation, definitely different properties from vector
17:58Chouserok
17:59Chouserjust checking. :-)
18:02ChouserI guess I knew the properties were very different from a vector, but I wondered if you wanted a mutable/immutable style instead of an always-immutable persistent finger tree.
18:03Chouserah, I misunderstood the api!
18:36rhickeyChouser: the immutable/mutable design is always based upon a pure immutable one
18:44wavisterdoes anyone else have trouble building a fresh pull of clojure-contrib?
18:45wavisterit says it can't locate walk.clj, which is part of the whole repo i just downloaded. seems like those paths should be set up correctly by default...
18:46Chousukehm
18:47Chousukedidn't walk move to Clojure itself when c.c.test-is did?
18:48Chousukethat might be the cause of your breakage. walk is no longer in contrib.
18:48Chousukeif you're using contrib with 1.0.0, checkout the clojure-1.0-compatible branch
18:49wavisterahhh that must be the thing
18:49wavisteror maybe i should get a newer clojure...?
18:51hiredmanyeah
18:55Chousukewavister: well, if you don't mind running clojure from git :P
18:56wavisteri don't mind.
19:00wavisteraaand it works! thanks!
19:55rhickeyhmm, PersistentVector in batch mode slightly faster than j.u.ArrayList!
19:56rhickeysorry, Vector
19:57rhickeyonly slightly slow than ArrayList
19:59rhickeyslower
20:01schaefer_i'm curious why the following doesn't work: (def (with-meta (symbol (str 't)) {:t "t"}) "t")
20:02schaefer_i get that def is a special form... is there a way to achieve the binding with a dynmically created symbol?
20:02rhickeyschaefer_: def is a special form that doesn't evaluate its first argument
20:03technomancymaybe this: (eval `(def ~(with-meta (symbol (str 't)) {:t "t"}) "t")) ?
20:03rhickey,(doc intern)
20:03clojurebotDENIED
20:03rhickey,(doc intern)
20:03clojurebotDENIED
20:03schaefer_i'm actually going through clojure.core and trying to understand why the defn macro works the way it does
20:04technomancyschaefer_: that works, but I don't think it's what you want wrt metadata
20:04rhickeywhy, clojurebot?
20:04technomancy(doc intern)
20:04clojurebotDENIED
20:04technomancyhiiiiiiiredman!
20:04rhickey,(doc rest)
20:04clojurebot"([coll]); Returns a possibly empty seq of the items after the first. Calls seq on its argument."
20:04rhickeyhrm
20:04Raynes(doc intern)
20:04clojurebotDENIED
20:05schaefer_well, what i ultimately want is a way to define a function with some meta data attached to it.
20:05technomancyschaefer_: metadata on the function or on the var?
20:06schaefer_good question. i think i want it on the var. i don't think you can attach metadata to a function (IFn does not subclass IObj)
20:06technomancyit's very tricky to do, in any case
20:07schaefer_how about this: how would you go about attaching additional metadata to an existing var?
20:08rhickeyit is definitely runtime metadata?
20:08schaefer_rhickey: yes, but i'm curious as opposed to what?
20:10rhickeyuser=> (def #^{:my :meta} foo 42)
20:10rhickey#'user/foo
20:10rhickeyuser=> ^#'foo
20:10rhickey{:ns #<Namespace user>, :name foo, :file "NO_SOURCE_PATH", :line 16, :my :meta}
20:11schaefer_can you translate that without the reader macros? i'm just learning and slowly coming up to speed
20:11schaefer_i'm really trying to get the basics of all this stuff down
20:13rhickeyschaefer_: well, the reader metadata is key, and thus the distinguishing point, getting at the meta can go like this:
20:13rhickeyuser=> (def #^{:when (java.util.Date.)} foo 42)
20:13rhickey#'user/foo
20:13rhickeyuser=> (meta (var foo))
20:13rhickey{:ns #<Namespace user>, :name foo, :file "NO_SOURCE_PATH", :line 24, :when #<Date Thu Jul 16 20:12:55 EDT 2009>}
20:14technomancyI'm not sure you can do the def without reader macros
20:15rhickey#^amap a-symbol-or-collection will read one object with attached metadata
20:15schaefer_ah... that could have been my failure when i was doing this on my own. i was trying to work it without the reader macro
21:06arohner,(name (var map))
21:06clojurebotjava.lang.ClassCastException: clojure.lang.Var cannot be cast to clojure.lang.Named
21:07Chouser,(.sym (var map))
21:07clojurebotmap
21:07Chouser,(.ns (var map))
21:07clojurebot#<Namespace clojure.core>
21:07arohneryeah, I knew the methods were on the var object
21:08arohnerjust found it weird that name didn't work on it
21:08Chouseryeah. me too.
21:08Chouserof course not all vars have a name
21:08arohneroh, right
21:08rhickeyArrayList
21:08rhickeytime: 1129
21:08rhickeyPersistentVector (batch mode)
21:08rhickeytime: 1354
21:08rhickeysmokin!
21:08arohnerwith-local-vars, etc
21:10rhickeywas:
21:10rhickeyPersistentVector
21:10rhickeytime: 3547
21:11Chouserwow
21:12Chousermuch too fast
21:12rhickeytruly crazy since you can, anywhere in the middle of the batch, say (immutable v) and get a perfectly fine immutable vector
21:12rhickeyand then keep going
21:12Chouserdoes the immutable thing persist like a regular PVector?
21:13rhickey(immutable v) being instantaneous
21:13rhickeyChouser: the immutable thing _is_ a pvector
21:13Chouseroh, same internal structure?
21:14rhickeythe mutable thing is almost a pvector, structurally similar so it can be 'adopted' as immutable in constant time
21:14Chouserah! cool.
21:14rhickeyprecisely same node structure
21:14rhickeyjust added a bit for editing
21:15rhickeyI'm still stunned at how fast the tree structure is
21:18rhickeythose times are for a million writes and 10 million reads of a 100k item arraylist/pvector
21:18rhickeyin ms
21:18Chouseris lazilypersistentvector still useful, or might you just as well build via mutable pvector at read time?
21:18rhickeyChouser: dunno yet, probably not needed now
21:19rhickeymost readable things are small, its vec/vector/into that are going to blaze now
21:20rhickeyand the mutable mode will be available for end user code as well
21:22rhickeyI prevent: using the mutable thing with the normal fns (conj etc), immutability of result of immutable call. Only caveat is against sharing the mutable thing - I can't help you then
21:22rhickeyer, protect immutability
21:23ChouserI really can't imagine it'll be a problem
21:23Chouseryou can use ArrayList today if you want to
21:23rhickeyexactly, but not with these features
21:24Chouserand if you accidentally forget to (immutable v) before you return it, either nobody will conj and it won't matter, or the case will be caught.
21:24Chouserright
21:24Chouserone key feature being exactly that latter protection.
21:25rhickeyand the free persistent 'copy', no copy involved
21:25Chouseryep. that free copy is one key way this is different from, say, google protobuf builders.
21:26rhickeythe pvector impl is still pretty gnarly
21:26rhickey:)
21:26Chouserheh. I don't doubt it.
21:26rhickeyrevisiting it was not fun
21:26Chouseroh!
21:26Chouseryou mean the way it was previously was gnarly?
21:26rhickeyyeah
21:27rhickeylots of bit shifts etc
21:27Chouserah, yes. I know that very well.
21:27ChouserDoesn't look any better in JavaScript.
21:28rhickeyone question is, how much functionality to put on the mutable versions, right now just basic assoc!, conj!, pop!, and nth!
21:28ChouserKinda doubt it will in Clojure either. ;-) what it's *doing* is gnarly.
21:29rhickeyChouser: I was trying to figure out today why that was - it's a recursive structure, but the tail etc just make it a pile of edge cases
21:29rhickeyalso it grows up, not down
21:31rhickeyin any case, these perf tests show it will be well worth it, no compromises in using Clojure's data structures
21:32rhickeyI think the technique will generalize to any tree
21:32rhickeyso once someone sees the vector, maybe they can do the maps
21:36Chouserwill be well worth what? having made this improvement to vector so that it can compete even better against plain mutable structures?
21:37rhickeyyes
21:37arohneryes, I can take advantage of a 3x performance boost
21:39rhickeyalso once you're at 1129/1354 you can say there's nothing substantial to be gained by switching to a java thingy
21:39Chouserdidn't we say that anyway? ;-)
21:40rhickeyYes, I thought at 2-4x it was worth writing Clojure
21:41rhickeythat was my target
21:41rhickeybut the question becomes, once you have a bottleneck, do you have to leave everything good behind?
21:42rhickeyswitch code radically
21:42Chouseryeah, that's similar to your response at the meetup to my all-too-frequent joke about speed.
21:42Chouserand it's a good response
21:43rhickeymy ultimate goal is to keep people away from Java mutable data structures other than j.u.concurrent, and away from arrays
21:43rhickeythe latter is the toughest nut to crack
21:43Chouserarrays are going to be ... yeah
21:44Chouservectors of primitives will help a lot of the memory-concious cases.
21:44rhickeybut all of this (incl chunks) paves the way for vectors of primitives
22:10mebaran151what would be the best way to test if a class is a given subclass of another class?
22:10hiredmanwell, if it's given then = should be fine
22:11hiredmanif you just want to test if a class is a subclass of another class, you can use isa?
22:11mebaran151isa? sounds right
22:12mebaran151but (isa? Exception IllegalArgumentException) returns false
22:12Chouserother way 'round
22:12skalnikClojure is awesome :)
22:13Chouser,(isa? IllegalArgumentException Exception)
22:13clojurebottrue
22:13mebaran151thanks Chouser, I wish I'd put it the right way at first
22:14Chouserarg ordering is frequently hard to guess at
22:14hiredman(doc isa?)
22:14clojurebot"([child parent] [h child parent]); Returns true if (= child parent), or child is directly or indirectly derived from parent, either via a Java type inheritance relationship or a relationship established via derive. h must be a hierarchy obtained from make-hierarchy, if not supplied defaults to the global hierarchy"
22:15_hrrldIt's so cool that the seq abstractions work on built-in Java objects.
22:20Chouserit's somewhat interesting that despite it's homoiconicity, the data structures used most commonly for runtime data are used least commonly to represent code.
22:21_hrrldIsn't that because most runtime data isn't code? ;) Everyone is choosing the structures most amenable to their data.
22:23Chouseryes, indeed! but that's rather different from older lisps.
22:23Chouser...where you had a list, so you generally made so with that for both code and data.
22:23_hrrldWhere the data structures to choose from were so much more limited.
22:23_hrrldyes.
22:24ChouserI don't think clojure's lists are particularly better at representing code than clojure's vectors would be.
22:24_hrrldWhat language will take advantage of array backed hash map tries for its code representation?
22:25ChouserIs the main benefit of using both lists and vectors in code that they stand out visually from each other?
22:25hiredmanI was talking to someone in #scala a few months back that wanted a homoiconic language based on maps
22:25hiredmanbut he might have just been winding me up
22:25Chouserhehe
22:25_hrrldFor nondeterministic evaluation!
22:26arohnerhiredman: there's a language like that
22:26arohnerit's a toy
22:26ChouserI've thought things like that before ... though I wanted order-preserving maps.
22:26Chouser...and that was before I knew lisp or what homoiconicity was.
22:26arohnerhttp://lambda-the-ultimate.org/node/2887
22:37mebaran151what would dispatch function look like that would choose a multimethod based on whether or not the selector was a parent?
22:38mebaran151kind of like dispatching with type except it wouldn't be strict equality
22:41hiredmanmultimethods don't dispatch on strict type equality
22:42hiredmanit wall walk up the hier if no equality exists
22:42mebaran151no I know, I'm trying to come up with a function that would dispatch this way
22:43mebaran151essentially I'm just passing in type right now as the dispatcher, but it would be nice to catch the class children too
22:43hiredmanerm
22:44hiredmanlisppaste8: url?
22:44lisppaste8To use the lisppaste bot, visit http://paste.lisp.org/new/clojure and enter your paste.
22:45lisppaste8hiredman pasted "defmulti example" at http://paste.lisp.org/display/83721
22:45hiredmanit sounds like that is what you want
22:45mebaran151http://clojure.pastebin.com/m48244d1b
22:46mebaran151but I don't know if it would catch the children too
22:46hiredmanit will catch subclasses of those two exceptions
22:46hiredmanbut you do the same thing for both
22:47mebaran151right now yes, but I'll handle them differently later
22:47mebaran151how does multimethod determine the match?
22:47hiredmanit checks for an exact match, then it walks the superclasses looking for a match
22:48mebaran151I thought it used whatever the the function returned, kind of like a dispatch table. Are the rules more nuanced?
22:48hiredmanyes
22:48hiredmanit is also possible to use heirarchies other then the java Class heirarchy
22:48mebaran151that was what I was looking for
22:49mebaran151so you can pass it a custom set of rules for determining what to consider a super and subclass?
22:49hiredman,(doc defmulti)
22:49clojurebot"([name docstring? attr-map? dispatch-fn & options]); Creates a new multimethod with the associated dispatch function. The docstring and attribute-map are optional. Options are key-value pairs and may be one of: :default the default dispatch value, defaults to :default :hierarchy the isa? hierarchy to use for dispatching defaults to the global hierarchy"
22:49hiredmanno
22:49hiredmanyou pass it a hierarchy
22:49hiredmanwhich it walks just like it would walk the Classes
22:50hiredmanmebaran151: http://clojure.org/multimethods
22:51mebaran151do the hierarchies always work in terms of symbols?
22:52hiredmanif you look at the link I just pasted, you will see hierarchies using keywords
22:55skalnikataggart: I got that infinite fib-seq done :)
22:57mebaran151thanks hiredman, I think I conflated symbols and keywords
22:58hiredman,(derive (Object.) :bob)
22:58clojurebotjava.lang.Exception: Assert failed: (namespace parent)
22:59hiredman,(doc derive)
22:59clojurebot"([tag parent] [h tag parent]); Establishes a parent/child relationship between parent and tag. Parent must be a namespace-qualified symbol or keyword and child can be either a namespace-qualified symbol or keyword or a class. h must be a hierarchy obtained from make-hierarchy, if not supplied defaults to, and modifies, the global hierarchy."
23:00Raynes(doc intern)
23:00clojurebotDENIED
23:06mebaran151anyway, thanks hiredman. I'm pleasantly surprised the default behavior of clojure
23:07hiredmanmultimethods are very cool
23:08grrrtspeaking of which... do all functions defined with defmethod need to be of the same arity?
23:08Chousernope
23:09grrrtspiffy
23:09hiredmanbut the dispatch function needs to be able to handle all the arities
23:09Chouserbut if the number of args you pass in cause either the dispatch fn or the method chosen to error out, then you get an error
23:09grrrta dispatch fn could then be (fn [&args] ....) i suppose?
23:09hiredman(comp type first list)
23:09Chouseryep
23:10grrrtI needed that a couple of days ago, can't remember what for though. but that's really cool
23:39gkoHow to key of a value in a map?
23:39gkohow to get key of value in a map?
23:40gkoOh... of course, no build in function, since value can be not unique..
23:40hiredman,(map #(.getName %) (.getMethods (class {})))
23:40clojurebot("seq" "withMeta" "withMeta" "withMeta" "assoc" "assoc" "valAt" "valAt" "entryAt" "without" "assocEx" "count" "iterator" "containsKey" "capacity" "empty" "empty" "create" "equiv" "invoke" "invoke" "get" "put" "hashCode" "clear" "equals" "toString" "isEmpty" "values" "size" "entrySet" "putAll" "cons" "remove" "keySet" "containsValue" "applyTo" "call" "applyToHelper" "throwArity" "invoke" "invoke" "invoke" "invoke" "invoke"