#clojure logs

2008-04-10

10:36drewrI added a lazy fibonacci function to http://en.wikibooks.org/wiki/Clojure_Programming#Examples. Any corrections/suggestions?
10:39MarkJPhow do I do the equivalent of MyClass.class in clojure?
10:40rhickeyMyClass is a Class?
10:40MarkJPyes
10:40MarkJPlike String
10:40MarkJPString.class gets me the Class instance
10:40MarkJPin Java
10:40rhickey(class String)
10:40rhickeylike all objects
10:41rhickeybut the result for any Class will always be Class
10:42MarkJPyeah, when I do (seq (. (class String) (getMethods)))
10:42MarkJPI don't get the String methods?
10:42rhickeybecause the class of the class String is Class
10:42MarkJPI get the Class and Object methods
10:42rhickeyyou want the String class itself
10:43rhickeywhich is just String
10:43rhickeybut the first position to . is not normally evaluated
10:43rhickeyso to get the String class object (instead of String class scope for static call) use identity
10:44rhickey(seq (. (identity String) (getMethods)))
10:44MarkJPawesome
10:44MarkJPthat's the trickl
10:44MarkJPthanks
10:44MarkJPdidn't know about identity
10:45rhickeyit just returns it's argument, but it's prevents the compiler from seeing String as a scope
10:45rhickeyits
10:51Chouserhm.. subtle.
10:52rhickeyWell, I didn't make classes scopes and objects with the same name, Java did :)
10:54MarkJPhmm
10:54MarkJPso this should work:
10:54MarkJP(map #(. (identity %) (getMethods)) '(FileWriter String))
10:54Chouserrhickey: wasn't critisizing, just a good detail to know.
10:55rhickeyChouser: I acknowledge the subtlety, and this comes up often, might be a good wiki tip
10:56MarkJPNo matching method found: getMethods
10:56drewrHow do you know to apply SEQ to "[Ljava.lang.reflect.Method;@6b340a"?
10:56rhickeyMark: no, . is a special op, it looks to see if the first arg designates a class, and treats it as a static call
10:56cgrandMark: (map #(. % (getMethods)) [FileWriter String])
10:57rhickey(list FileWriter String) is a list of classes, '(FileWriter String) is a list of Symbols
10:57MarkJPcgrand: sameproblem
10:57rhickeyidentity trick is only when you want to use a class _object_ by name directly after .
10:58rhickey(let [x String] (. x getMethods))
10:59cgrandmarkjp: strange, I get ([Ljava.lang.reflect.Method;@ec436 [Ljava.lang.reflect.Method;@173eca6)
10:59rhickeyMark: cgrand's is right, (map #(. % (getMethods)) [java.io.FileWriter String])
11:00rhickeyreturns seq of arrays of Methods
11:00MarkJPyep sorry, cgrand was right
11:00MarkJPthx
11:02rhickeydrewr: "[..." is the way Java arrays print toString, and Method[] is the documented return type of GetMethods, and seq works on Java arrays
11:03rhickeywhen I do readable Java objects, I'll change prn to print arrays readably
11:05drewrrhickey: OK, thanks.
11:12rhickeydrewr: re: fib, if you want to end up with a seq, that people use with take, nth etc, then you might want to consider using a seq directly, rather than have them call a fn:
11:12rhickey(def fib
11:12rhickey (concat
11:12rhickey [0 1]
11:12rhickey ((fn rfib [a b]
11:12rhickey (lazy-cons (+ a b) (rfib b (+ a b)))) 0 1)))
11:13rhickeyuser=> (time (nth fib 1000))
11:13rhickey"Elapsed time: 3.732 msecs"
11:13rhickeysecond time:
11:13rhickeyuser=> (time (nth fib 1000))
11:13rhickey"Elapsed time: 0.671 msecs"
11:15rhickeyIf you stick with a fib function, it will be recalculated every time. In any case I think you need to hide the 2-arg helper fn, as no-one will know what to do with it
11:29drewrYeah, that's much cleaner. My concat didn't feel right.
11:34drewrrhickey_: I understand why yours is cleaner (and I was wondering how to make a lexical function like that), but why is mine so much slower? Should the original (fib 0 1) only get called once and return the lazy-cons?
11:35rhickey_your's isn't slower the first time, but every time someone calls (fib) they start over, mine is essentially a cached infinite seq, lazily extended
11:36drewrAhhh. That's wicked cool.
11:37drewrI do get an error with yours though:
11:37drewruser> (take 20 (fib-rich))
11:37drewrjava.lang.ClassCastException: clojure.lang.FnSeq
11:37rhickey_mine is not a function, no parens needed
11:38rhickey_(take 20 fib-rich)
11:39drewrOK, you're just wrapping the real function with a [0 1] seed. That's what I was essentially trying to do but didn't know how.
11:39drewrIn Scheme, you'd just (define fib... (define rfib... )) and I couldn't figure out how to replicate that.
11:40rhickey_it's not exactly like that - that's the lexical part, but the expression (concat ...) that initializes fib returns an infinite seq, fib just holds the seq
11:40rhickey_fib is not a function
11:41drewrI understand. It's just giving a name to a sequence that starts with [0 1] and ends with an infinite one.
11:41rhickey_right
14:51drewrCan I specify a default value for a function arg?
14:51drewr...like Python, def foo(bar=None): pass.
14:53Chousernope, but you can specify multiple arities for your function, like this...
14:53drewrI need basically the same code for each arity though.
14:53drewrI don't want to repeat it.
14:53Chouser(defn foo ([] (foo nil)) ([bar] (...)))
14:54drewrI could use (defn [& bar] (if bar ...)) I guess.
14:54Chouseroh! right, if you want them to all default to nil.
14:54drewrYeah, I just want to optionally pass it.
14:55Chouserin fact, then you could do: (defn foo [& [bar]] ...)
14:56drewrWhy not [& bar] ?
14:56Chouserbar would then be a seq
14:57Chouserthere can only be one thing after &, and it gets a seq of all remaining actual parameters.
14:58Chouser...unless that one thing is a list (like [& [bar]]) in which case it too gets deconstructed.
14:58ChouserIf you have multiple optional args that you want to each default to nil, you can use this pattern: [& [x & [y & z]]]
14:58Chouseroops, I mean: [& [x & [y & [z]]]]
15:00drewrOr [& [x y z]] ?
15:02Chouserno, that throws an exception if you dont have at least 3 items
15:02Chouserjust like [x y z]
15:02ChouserUsing & and wrapping the next level in [] all the way down keeps each next level optiona.
15:02Chouseroptional.
15:04drewrAh.
15:14ChouserI guess I should say the & keeps the next level optional, and the [] deconstructs that next level.
15:18abrooksDoes this ask for a: (defmacro varargs ...) // (defn foo [(varargs x y z)] ...)
15:18abrooksvarargs may be too specific but I can't think of other places that you'd use that construct.
15:19ChouserI was thinking about that. Have you tried it? Will a macro be evaluated inside a binding construct like that?
15:19Chousermy guess is no.
15:23ChouserThe binding forms are walked by the clojure/destructure function, not evaluated, so it looks like a macro there won't be called.
15:24ChouserYou'd have to put the macro on the outside of the defn.
15:35abrooksChouser: You're right, of course. Since the application is mostly specific you could create the few fnvar/defnvar or whatever macro wrappers for fn/defn.
15:36abrooks^mostly specific^specific to functions
15:51Chouserabrooks: it still seems like it'd be pretty tricky. Wouldn't you have to define your whole own destructering system?
15:56rhickey_(defn foo [& [a b c]]
15:56rhickey_ [a b c])
15:56rhickey_user=> (foo)
15:56rhickey_[nil nil nil]
15:56rhickey_user=> (foo 1)
15:56rhickey_[1 nil nil]
15:56rhickey_user=> (foo 1 2)
15:56rhickey_[1 2 nil]
15:56rhickey_user=> (foo 1 2 3)
15:56rhickey_[1 2 3]
15:58Chouserack!
15:59Chouserdrewr: I lied to you.
16:00ChouserMan, I really thought I had tried that.
16:04jgracinyay! When I press Super-a with cursor (point, that is) over some Clojure var in Emacs, I get its arglists printed in the minibuffer.
16:05rhickey_jgracin: with what clojure-mode version?
16:05abrooksEr. Not vimpact, vimpulse.
16:06jgracinwith your socket-repl code and a couple of funcs written by me. not touched(integrated into) clojure-mode.
16:08rhickey_anyone try swank-clojure from: http://clojure.codestuffs.com/ ?
16:12jgracinrhickey_: oh, I didn't know about that. that looks cool.
16:16drewrrhickey_: Yes, I've been using it for a few days and it's really good.
16:17rhickey_drewr: what does it add over clojure-mode?
16:18drewrAll the goodness that SLIME/swank gives you... ad hoc function prototypes, more tightly integrated REPL & code buffer, and soon dynamic introspection.
16:19drewrI remember you saying you were a LW guy.
16:19rhickey_right
16:23Chouserswank-clojure doesn't support debugging yet, does it? breakpoints, stepping, etc?
16:26drewrChouser: No, and I'm not sure what's involved with that. I asked rhickey_ about conditions/restarts in Clojure because I wondered if it's required.
16:27Chouserah
16:27drewrMaking the stacktrace/debugging process more CL-like would help a lot.
16:28drewrI'm not sure if the onus is on Clojure or SLIME for the bulk of that.
16:32rhickey_it's hard for me to imagine that approach bettering JVM debuggers - Clojure is all wired for that
16:35drewrDo you forsee an exception abstraction between Clojure and Java for things that only make sense to Clojure?
16:36rhickey_like what?
16:38drewrTake my earlier problem for example. `(def a (seq (1 2 3))) (take 10 (a))' yields a ClassCastException with FnSeq because A isn't a function.
16:39drewrThat seems counterintuitive, and a little orthogonal to the problem at hand.
16:39drewrCan't Clojure tell me that A can't be used in a callable context or something?
16:39rhickey_hmmm... wrap every call in a try/catch?
16:40drewrI know that the objective isn't to hide Java from the end user, but it seems like some things could be wrapped.
16:40drewrOh, so that's what it would take? Wrapping every eval?
16:40rhickey_I just wish the CastClass message said both the type you had and the type required
16:40drewrHeh. That would help a lot.
16:41rhickey_wrapping eval wouldn't give you the granularity to know what was wrong
16:42rhickey_fn calls are fast because they are cast and call, there is no conditional aspect to them
16:43drewrAh. So does the JVM not give you the information to really make it worthwhile anyway.
16:43drewr./?
16:44rhickey_I could instead do instanceof IFn and conditional branch, but at a perf cost
16:45rhickey_fn call speed is pretty imprtant
16:45rhickey_to me
16:45drewrI'll just learn how to interpret the Java stacktraces (I'm getting better).
16:45drewrI don't want Clojure to be such a thick layer on top of Java that it's counterproductive.
16:47rhickey_There is definite room for improvement in error messages, the one you chose though is a critical area, I think the onus is on Java to improve that message, it seems obviously deficient - maybe it is a security thing?
16:49drewrPerhaps, though that would seem ridiculous. Why lay out the entire call stack and then the one piece of evidence you need?
16:49drewrI don't have enough experience with Java to know if they make decisions like that.
16:50rhickey_caster could be casting to a class private to it, reported castee type is known to the caller
17:38rhickey_cgrand: having trouble getting breakpoints set with the Eclipse plugin...
17:38rhickey_anything special one needs to do? I just dropped the jar in plugins/ and restarted
17:39rhickey_made a remote debug connection to a Clojure instance
17:39rhickey_open boot.clj in Eclipse, refuses to let me set breakpoints
19:05ericthor#thortech
19:06ericthoropps...wrong window