2008-04-10
| 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 | MarkJP | like String |
| 10:40 | MarkJP | String.class gets me the Class instance |
| 10:40 | MarkJP | in Java |
| 10:40 | rhickey | (class String) |
| 10:40 | rhickey | like all objects |
| 10:41 | rhickey | but the result for any Class will always be Class |
| 10:42 | MarkJP | yeah, when I do (seq (. (class String) (getMethods))) |
| 10:42 | MarkJP | 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 | rhickey | which is just String |
| 10:43 | rhickey | but the first position to . is not normally evaluated |
| 10:43 | rhickey | so to get the String class object (instead of String class scope for static call) use identity |
| 10:44 | rhickey | (seq (. (identity String) (getMethods))) |
| 10:44 | MarkJP | awesome |
| 10:44 | MarkJP | that's the trickl |
| 10:44 | MarkJP | thanks |
| 10:44 | MarkJP | 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 | rhickey | 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 | MarkJP | so this should work: |
| 10:54 | MarkJP | (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 | rhickey | (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 | rhickey | returns seq of arrays of Methods |
| 11:00 | MarkJP | yep sorry, cgrand was right |
| 11:00 | MarkJP | 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 | rhickey | 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 | rhickey | (def fib |
| 11:12 | rhickey | (concat |
| 11:12 | rhickey | [0 1] |
| 11:12 | rhickey | ((fn rfib [a b] |
| 11:12 | rhickey | (lazy-cons (+ a b) (rfib b (+ a b)))) 0 1))) |
| 11:13 | rhickey | user=> (time (nth fib 1000)) |
| 11:13 | rhickey | "Elapsed time: 3.732 msecs" |
| 11:13 | rhickey | second time: |
| 11:13 | rhickey | user=> (time (nth fib 1000)) |
| 11:13 | rhickey | "Elapsed time: 0.671 msecs" |
| 11:15 | rhickey | 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 | drewr | 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 | drewr | I do get an error with yours though: |
| 11:37 | drewr | user> (take 20 (fib-rich)) |
| 11:37 | drewr | java.lang.ClassCastException: clojure.lang.FnSeq |
| 11:37 | rhickey_ | mine is not a function, no parens needed |
| 11:38 | rhickey_ | (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 | drewr | 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 | rhickey_ | 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 | drewr | ...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 | drewr | 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 | Chouser | there can only be one thing after &, and it gets a seq of all remaining actual parameters. |
| 14:58 | Chouser | ...unless that one thing is a list (like [& [bar]]) in which case it too gets deconstructed. |
| 14:58 | Chouser | If you have multiple optional args that you want to each default to nil, you can use this pattern: [& [x & [y & z]]] |
| 14:58 | Chouser | 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 | Chouser | just like [x y z] |
| 15:02 | Chouser | Using & and wrapping the next level in [] all the way down keeps each next level optiona. |
| 15:02 | Chouser | 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 | abrooks | 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 | Chouser | my guess is no. |
| 15:23 | Chouser | 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 | Chouser | 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 | abrooks | ^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 | rhickey_ | [a b c]) |
| 15:56 | rhickey_ | user=> (foo) |
| 15:56 | rhickey_ | [nil nil nil] |
| 15:56 | rhickey_ | user=> (foo 1) |
| 15:56 | rhickey_ | [1 nil nil] |
| 15:56 | rhickey_ | user=> (foo 1 2) |
| 15:56 | rhickey_ | [1 2 nil] |
| 15:56 | rhickey_ | user=> (foo 1 2 3) |
| 15:56 | rhickey_ | [1 2 3] |
| 15:58 | Chouser | ack! |
| 15:59 | Chouser | drewr: I lied to you. |
| 16:00 | Chouser | 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:05 | rhickey_ | jgracin: with what clojure-mode version? |
| 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: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 | drewr | 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: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 | drewr | That seems counterintuitive, and a little orthogonal to the problem at hand. |
| 16:39 | drewr | 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 | drewr | 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 | rhickey_ | 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 | drewr | ./? |
| 16:44 | rhickey_ | I could instead do instanceof IFn and conditional branch, but at a perf cost |
| 16:45 | rhickey_ | fn call speed is pretty imprtant |
| 16:45 | rhickey_ | to me |
| 16:45 | drewr | I'll just learn how to interpret the Java stacktraces (I'm getting better). |
| 16:45 | drewr | 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 | drewr | 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 | rhickey_ | cgrand: having trouble getting breakpoints set with the Eclipse plugin... |
| 17:38 | rhickey_ | anything special one needs to do? I just dropped the jar in plugins/ and restarted |
| 17:39 | rhickey_ | made a remote debug connection to a Clojure instance |
| 17:39 | rhickey_ | open boot.clj in Eclipse, refuses to let me set breakpoints |
| 19:05 | ericthor | #thortech |
| 19:06 | ericthor | opps...wrong window |