#clojure log - Apr 10 2008

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

10:36 drewr: I added a lazy fibonacci function to http://en.wikibooks.org/wiki/Clojure_Programming#Examples. Any corrections/suggestions?

10:39 MarkJP: how do I do the equivalent of MyClass.class in clojure?

10:40 rhickey: MyClass is a Class?

10:40 MarkJP: yes

10:40 like String

10:40 String.class gets me the Class instance

10:40 in Java

10:40 rhickey: (class String)

10:40 like all objects

10:41 but the result for any Class will always be Class

10:42 MarkJP: yeah, when I do (seq (. (class String) (getMethods)))

10:42 I don't get the String methods?

10:42 rhickey: because the class of the class String is Class

10:42 MarkJP: I get the Class and Object methods

10:42 rhickey: you want the String class itself

10:43 which is just String

10:43 but the first position to . is not normally evaluated

10:43 so to get the String class object (instead of String class scope for static call) use identity

10:44 (seq (. (identity String) (getMethods)))

10:44 MarkJP: awesome

10:44 that's the trickl

10:44 thanks

10:44 didn't know about identity

10:45 rhickey: it just returns it's argument, but it's prevents the compiler from seeing String as a scope

10:45 its

10:51 Chouser: hm.. subtle.

10:52 rhickey: Well, I didn't make classes scopes and objects with the same name, Java did :)

10:54 MarkJP: hmm

10:54 so this should work:

10:54 (map #(. (identity %) (getMethods)) '(FileWriter String))

10:54 Chouser: rhickey: wasn't critisizing, just a good detail to know.

10:55 rhickey: Chouser: I acknowledge the subtlety, and this comes up often, might be a good wiki tip

10:56 MarkJP: No matching method found: getMethods

10:56 drewr: How do you know to apply SEQ to "[Ljava.lang.reflect.Method;@6b340a"?

10:56 rhickey: Mark: no, . is a special op, it looks to see if the first arg designates a class, and treats it as a static call

10:56 cgrand: Mark: (map #(. % (getMethods)) [FileWriter String])

10:57 rhickey: (list FileWriter String) is a list of classes, '(FileWriter String) is a list of Symbols

10:57 MarkJP: cgrand: sameproblem

10:57 rhickey: identity trick is only when you want to use a class _object_ by name directly after .

10:58 (let [x String] (. x getMethods))

10:59 cgrand: markjp: strange, I get ([Ljava.lang.reflect.Method;@ec436 [Ljava.lang.reflect.Method;@173eca6)

10:59 rhickey: Mark: cgrand's is right, (map #(. % (getMethods)) [java.io.FileWriter String])

11:00 returns seq of arrays of Methods

11:00 MarkJP: yep sorry, cgrand was right

11:00 thx

11:02 rhickey: drewr: "[..." is the way Java arrays print toString, and Method[] is the documented return type of GetMethods, and seq works on Java arrays

11:03 when I do readable Java objects, I'll change prn to print arrays readably

11:05 drewr: rhickey: OK, thanks.

11:12 rhickey: drewr: 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:12 (def fib

11:12 (concat

11:12 [0 1]

11:12 ((fn rfib [a b]

11:12 (lazy-cons (+ a b) (rfib b (+ a b)))) 0 1)))

11:13 user=> (time (nth fib 1000))

11:13 "Elapsed time: 3.732 msecs"

11:13 second time:

11:13 user=> (time (nth fib 1000))

11:13 "Elapsed time: 0.671 msecs"

11:15 If 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:29 drewr: Yeah, that's much cleaner. My concat didn't feel right.

11:34 rhickey_: 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:35 rhickey_: 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:36 drewr: Ahhh. That's wicked cool.

11:37 I do get an error with yours though:

11:37 user> (take 20 (fib-rich))

11:37 java.lang.ClassCastException: clojure.lang.FnSeq

11:37 rhickey_: mine is not a function, no parens needed

11:38 (take 20 fib-rich)

11:39 drewr: OK, 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:39 In Scheme, you'd just (define fib... (define rfib... )) and I couldn't figure out how to replicate that.

11:40 rhickey_: 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:40 fib is not a function

11:41 drewr: I understand. It's just giving a name to a sequence that starts with [0 1] and ends with an infinite one.

11:41 rhickey_: right

14:51 drewr: Can I specify a default value for a function arg?

14:51 ...like Python, def foo(bar=None): pass.

14:53 Chouser: nope, but you can specify multiple arities for your function, like this...

14:53 drewr: I need basically the same code for each arity though.

14:53 I don't want to repeat it.

14:53 Chouser: (defn foo ([] (foo nil)) ([bar] (...)))

14:54 drewr: I could use (defn [& bar] (if bar ...)) I guess.

14:54 Chouser: oh! right, if you want them to all default to nil.

14:54 drewr: Yeah, I just want to optionally pass it.

14:55 Chouser: in fact, then you could do: (defn foo [& [bar]] ...)

14:56 drewr: Why not [& bar] ?

14:56 Chouser: bar would then be a seq

14:57 there can only be one thing after &, and it gets a seq of all remaining actual parameters.

14:58 ...unless that one thing is a list (like [& [bar]]) in which case it too gets deconstructed.

14:58 If you have multiple optional args that you want to each default to nil, you can use this pattern: [& [x & [y & z]]]

14:58 oops, I mean: [& [x & [y & [z]]]]

15:00 drewr: Or [& [x y z]] ?

15:02 Chouser: no, that throws an exception if you dont have at least 3 items

15:02 just like [x y z]

15:02 Using & and wrapping the next level in [] all the way down keeps each next level optiona.

15:02 optional.

15:04 drewr: Ah.

15:14 Chouser: I guess I should say the & keeps the next level optional, and the [] deconstructs that next level.

15:18 abrooks: Does this ask for a: (defmacro varargs ...) // (defn foo [(varargs x y z)] ...)

15:18 varargs may be too specific but I can't think of other places that you'd use that construct.

15:19 Chouser: I was thinking about that. Have you tried it? Will a macro be evaluated inside a binding construct like that?

15:19 my guess is no.

15:23 The binding forms are walked by the clojure/destructure function, not evaluated, so it looks like a macro there won't be called.

15:24 You'd have to put the macro on the outside of the defn.

15:35 abrooks: Chouser: 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:36 ^mostly specific^specific to functions

15:51 Chouser: abrooks: it still seems like it'd be pretty tricky. Wouldn't you have to define your whole own destructering system?

15:56 rhickey_: (defn foo [& [a b c]]

15:56 [a b c])

15:56 user=> (foo)

15:56 [nil nil nil]

15:56 user=> (foo 1)

15:56 [1 nil nil]

15:56 user=> (foo 1 2)

15:56 [1 2 nil]

15:56 user=> (foo 1 2 3)

15:56 [1 2 3]

15:58 Chouser: ack!

15:59 drewr: I lied to you.

16:00 Man, I really thought I had tried that.

16:04 jgracin: yay! 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:04 * abrooks is filled with emacs envy.

16:05 rhickey_: jgracin: with what clojure-mode version?

16:05 * abrooks really needs to get viper/vimpact setup.

16:05 abrooks: Er. Not vimpact, vimpulse.

16:06 jgracin: with your socket-repl code and a couple of funcs written by me. not touched(integrated into) clojure-mode.

16:08 rhickey_: anyone try swank-clojure from: http://clojure.codestuffs.com/ ?

16:12 jgracin: rhickey_: oh, I didn't know about that. that looks cool.

16:16 drewr: rhickey_: Yes, I've been using it for a few days and it's really good.

16:17 rhickey_: drewr: what does it add over clojure-mode?

16:18 drewr: All the goodness that SLIME/swank gives you... ad hoc function prototypes, more tightly integrated REPL & code buffer, and soon dynamic introspection.

16:18 * rhickey_ never used slime

16:19 drewr: I remember you saying you were a LW guy.

16:19 rhickey_: right

16:23 Chouser: swank-clojure doesn't support debugging yet, does it? breakpoints, stepping, etc?

16:26 drewr: Chouser: 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:27 Chouser: ah

16:27 drewr: Making the stacktrace/debugging process more CL-like would help a lot.

16:28 I'm not sure if the onus is on Clojure or SLIME for the bulk of that.

16:32 rhickey_: it's hard for me to imagine that approach bettering JVM debuggers - Clojure is all wired for that

16:32 * rhickey_ needs to try cgrand's Eclipse debugger plugin

16:35 drewr: Do you forsee an exception abstraction between Clojure and Java for things that only make sense to Clojure?

16:36 rhickey_: like what?

16:38 drewr: Take 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:39 That seems counterintuitive, and a little orthogonal to the problem at hand.

16:39 Can't Clojure tell me that A can't be used in a callable context or something?

16:39 rhickey_: hmmm... wrap every call in a try/catch?

16:40 drewr: I know that the objective isn't to hide Java from the end user, but it seems like some things could be wrapped.

16:40 Oh, so that's what it would take? Wrapping every eval?

16:40 rhickey_: I just wish the CastClass message said both the type you had and the type required

16:40 drewr: Heh. That would help a lot.

16:41 rhickey_: wrapping eval wouldn't give you the granularity to know what was wrong

16:42 fn calls are fast because they are cast and call, there is no conditional aspect to them

16:43 drewr: Ah. So does the JVM not give you the information to really make it worthwhile anyway.

16:43 ./?

16:44 rhickey_: I could instead do instanceof IFn and conditional branch, but at a perf cost

16:45 fn call speed is pretty imprtant

16:45 to me

16:45 drewr: I'll just learn how to interpret the Java stacktraces (I'm getting better).

16:45 I don't want Clojure to be such a thick layer on top of Java that it's counterproductive.

16:47 rhickey_: 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:49 drewr: Perhaps, though that would seem ridiculous. Why lay out the entire call stack and then the one piece of evidence you need?

16:49 I don't have enough experience with Java to know if they make decisions like that.

16:50 rhickey_: caster could be casting to a class private to it, reported castee type is known to the caller

17:38 cgrand: having trouble getting breakpoints set with the Eclipse plugin...

17:38 anything special one needs to do? I just dropped the jar in plugins/ and restarted

17:39 made a remote debug connection to a Clojure instance

17:39 open boot.clj in Eclipse, refuses to let me set breakpoints

19:05 ericthor: #thortech

19:06 opps...wrong window

Logging service provided by n01se.net