Re: Blow up
Your analysis is correct. Note that adding a doall fixes the problem user= (def tl (reduce #(doall (concat %1 [%2])) [] (range 4000))) #'user/tl user= (last tl) 3999 efficiency notwithstanding. On Mar 28, 8:59 am, jim jim.d...@gmail.com wrote: Hey Rich, I found an interesting way to blow up the stack. user= (def tl (reduce #(concat %1 [%2]) [] (range 3500))) #'user/tl user= (last tl) java.lang.StackOverflowError (NO_SOURCE_FILE:0) The 3500 is probably specific to my environment. I'm assuming that all the concats get deferred until needed and that the nested calls blow up the stack. Also, this works user= (def tl (reduce #(conj %1 %2) [] (range 4000))) #'user/tl user= (last tl) 3999 Jim --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~--~~~~--~~--~--~---
Re: oo
On Sat, Mar 28, 2009 at 4:40 PM, mikel mev...@mac.com wrote: So, at minimum, to make a solid port, you need to add a function that can return a sensible type value for any input Enjoying the thread. Out of curiosity for which Clojure values is the return value of the type function undefined? David --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~--~~~~--~~--~--~---
Possible Solution for Left-Right Precedence and More when using Multimethods? (was re: oo)
Having thought a little about multiple inheritance when implementing Spinoza I also ran into this problem. However at the time I wasn't hindered by multifn dispatch as much as the fact that parents cannot be ordered (because calling parents on a tag returns a set) as pointed out by Mark. I understand Rich's point that hierarchies probably shouldn't be directional, but for the sake of practicality why not allow the programmer to specify that a tag (or even the whole hierarchy) should in fact have its relationships be ordered? In general prefer-method seemed to me (I could be wrong) to be a last attempt solution- when there is just no other way to resolve an ambiguity, and this ambiguity is not of the hierarchy, but of multimethod dispatch. As pointed out by Konrad Rich, you can work around the limitation of hierarchies right now with a lot of prefer-methods. But as Mikel points out, with current state of prefer-method you have to hunt through code to find out where these prefers were made and for what reason and they assume that you've already written your methods (this for me is the deal breaker). In anycase my general feeling (in agreement with Mark) is that the problem isn't with multifns but rather with how hierarchies are constructed. So the achilles heel of hierarchies seems to be that when you call parents (and related fns) on a tag you get a set - it has no order. For single inheritance hierarchies this is fine, but for multiple inheritance I think this becomes a problem a very fast. Working on Spinoza, I realized I would have to keep my own ordered list of parents in order to support left-right precedence, basically keeping an ordered copy of the whole hierarchy. Again prefer-method is only useful for fixing method-level ambiguities. There's no general way to say, type A always precedes type B without writing quite a bit of explicit code (or hiding the problem away with macros). Here's something that might kick of a dicussion to a proper solution (I am sure there are some gaps in my logic), why not allow something like the following? ;; allow control of how tags get introduced into the hierarchy (def h (make-hierarchy :parents-fn fn1 :ancestors-fn fn2 :descendants-fn fn3)) ;; add a new parent insertion fn to a hierarchy (add-parents-fn h fn4) ;; - returns a new hierarchy with the parents fn set, all parents sets are converted into vectors ;; add a new parent insertion fn to a hierarchy for a specific key, only the parents of ::my-tag are converted into a vector (add-parents-fn h fn4 ::my-tag) ;; a hierarchy fn might look something like the following (defn my-parents-fn [parents new-key] (conj parents new-key)) If my thinking is correct this is pretty flexible. This doesn't break the meaning of hierarchy for any existing code. It doesn't change the signature of multimethods. Yet now a user can provide fns that sorts a hierarchy anyway they please, and it doesn't even have to be the entire hierarchy. This code will probably live in one spot where anyone could look to understand how the hierarchy is being constructed. All high-level precedence ambiguities can now be resolved by looking at the hierarchy. prefer-method does only what it was intended to do- resolve method level ambiguity. David --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~--~~~~--~~--~--~---
Request for improved error reporting
Hi, I've been really enjoying getting to know clojure. It's an awesome language that has got me very interested in learning more. One thing that hasn't left me impressed is the error reporting. I recently got this one that left me scratching my head: java.lang.NullPointerException (splat.clj:0) at clojure.lang.Compiler.eval(Compiler.java:4533) at clojure.lang.Compiler.load(Compiler.java:4846) at clojure.lang.Compiler.loadFile(Compiler.java:4813) at clojure.main$load_script__5793.invoke(main.clj:206) at clojure.main$script_opt__5824.invoke(main.clj:258) at clojure.main$main__5848$fn__5850.invoke(main.clj:333) at clojure.main$main__5848.doInvoke(main.clj:328) at clojure.lang.RestFn.invoke(RestFn.java:413) at clojure.lang.Var.invoke(Var.java:346) at clojure.lang.AFn.applyToHelper(AFn.java:173) at clojure.lang.Var.applyTo(Var.java:463) at clojure.main.main(main.java:39) Caused by: java.lang.NullPointerException at user$render_layer__37.invoke(splat.clj:311) at user$render_layers__40.invoke(splat.clj:315) at user$active_update__43.invoke(splat.clj:323) at user$run__55.invoke(splat.clj:349) at user$eval__58.invoke(splat.clj:378) at clojure.lang.Compiler.eval(Compiler.java:4522) ... 11 more There are a few things wrong here and with clojure error reporting in general: 1. I'm not getting a line number for some reason. 2. I don't get any indication what the nature of the error is. 3. I get a big (nested) stack trace that has more to do with clojure compiler internals than my program. Even when clojure does tell you what went wrong I don't really need to see the compiler internals. Just the parts relevant to my program. Perhaps some context (such as printing the source line causing the problem) and a clear message stating the nature of the problem. Regards, Glen --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~--~~~~--~~--~--~---
Re: Request for improved error reporting
Sorry I just realized I was a bit ambiguous with this. The exception does show the line number (in the second stack trace). But it's gone missing in the top one. 2009/3/29 Glen Stampoultzis gst...@gmail.com Hi, I've been really enjoying getting to know clojure. It's an awesome language that has got me very interested in learning more. One thing that hasn't left me impressed is the error reporting. I recently got this one that left me scratching my head: java.lang.NullPointerException (splat.clj:0) at clojure.lang.Compiler.eval(Compiler.java:4533) at clojure.lang.Compiler.load(Compiler.java:4846) at clojure.lang.Compiler.loadFile(Compiler.java:4813) at clojure.main$load_script__5793.invoke(main.clj:206) at clojure.main$script_opt__5824.invoke(main.clj:258) at clojure.main$main__5848$fn__5850.invoke(main.clj:333) at clojure.main$main__5848.doInvoke(main.clj:328) at clojure.lang.RestFn.invoke(RestFn.java:413) at clojure.lang.Var.invoke(Var.java:346) at clojure.lang.AFn.applyToHelper(AFn.java:173) at clojure.lang.Var.applyTo(Var.java:463) at clojure.main.main(main.java:39) Caused by: java.lang.NullPointerException at user$render_layer__37.invoke(splat.clj:311) at user$render_layers__40.invoke(splat.clj:315) at user$active_update__43.invoke(splat.clj:323) at user$run__55.invoke(splat.clj:349) at user$eval__58.invoke(splat.clj:378) at clojure.lang.Compiler.eval(Compiler.java:4522) ... 11 more There are a few things wrong here and with clojure error reporting in general: 1. I'm not getting a line number for some reason. 2. I don't get any indication what the nature of the error is. 3. I get a big (nested) stack trace that has more to do with clojure compiler internals than my program. Even when clojure does tell you what went wrong I don't really need to see the compiler internals. Just the parts relevant to my program. Perhaps some context (such as printing the source line causing the problem) and a clear message stating the nature of the problem. Regards, Glen --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~--~~~~--~~--~--~---
Re: Request for improved error reporting
It wasn't really this specific problem that I wanted to point out but more to trigger a rethink of how errors are reported back to the user. Here's an example that gives an error somewhat similar to the one I posted: (defn testing [a b] (print a b)) (testing) java.lang.NoSuchMethodError: java.lang.Class.getSimpleName()Ljava/lang/String; (testing.clj:0) at clojure.lang.Compiler.eval(Compiler.java:4533) at clojure.lang.Compiler.load(Compiler.java:4846) at clojure.lang.Compiler.loadFile(Compiler.java:4813) at clojure.main$load_script__5793.invoke(main.clj:206) at clojure.main$script_opt__5824.invoke(main.clj:258) at clojure.main$main__5848$fn__5850.invoke(main.clj:333) at clojure.main$main__5848.doInvoke(main.clj:328) at clojure.lang.RestFn.invoke(RestFn.java:413) at clojure.lang.Var.invoke(Var.java:346) at clojure.lang.AFn.applyToHelper(AFn.java:173) at clojure.lang.Var.applyTo(Var.java:463) at clojure.main.main(main.java:39) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:582) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:90) Caused by: java.lang.NoSuchMethodError: java.lang.Class.getSimpleName()Ljava/lang/String; at clojure.lang.AFn.throwArity(AFn.java:447) at clojure.lang.AFn.invoke(AFn.java:48) at user$eval__4.invoke(testing.clj:3) at clojure.lang.Compiler.eval(Compiler.java:4522) ... 16 more Using latest released version of clojure. 2009/3/29 Stephen C. Gilardi squee...@mac.com On Mar 28, 2009, at 8:01 PM, Glen Stampoultzis wrote: Sorry I just realized I was a bit ambiguous with this. The exception does show the line number (in the second stack trace). But it's gone missing in the top one. Is this with the current svn or most recent release of Clojure? It would be helpful if you could post a (small) reproducible recipe for a test case that shows the problem. --Steve --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~--~~~~--~~--~--~---
Re: new in contrib.test-is: fixtures
very cool :) On 3/28/09, Stuart Sierra the.stuart.sie...@gmail.com wrote: Hi folks, I finally came up with fixtures for clojure.contrib.test-is. Now you can do before/after setup for each test case. Here's the documentation, let me know what you think. -Stuart Sierra ;; FIXTURES (new) ;; ;; Fixtures allow you to run code before and after tests, to set up ;; the context in which tests should be run. ;; ;; A fixture is just a function that calls another function passed as ;; an argument. It looks like this: (defn my-fixture [f] ;; Perform setup, establish bindings, whatever. (f) ;; Then call the function we were passed. ;; Tear-down / clean-up code here. ) ;; Fixtures are attached to namespaces in one of two ways. each ;; fixtures are run repeatedly, once for each test function created ;; with deftest or with-test. each fixtures are useful for ;; establishing a consistent before/after state for each test, like ;; clearing out database tables. ;; ;; each fixtures can be attached to the current namespace like this: (use-fixtures :each fixture1 fixture2 ...) ;; The fixture1, fixture2 are just functions like the example above. ;; They can also be anonymous functions, like this: (use-fixtures :each (fn [f] setup... (f) cleanup...)) ;; ;; The other kind of fixture, a once fixture, is only run once, ;; around ALL the tests in the namespace. once fixtures are useful ;; for tasks that only need to be performed once, like establishing ;; database connections, or for time-consuming tasks. ;; ;; Attach once fixtures to the current namespace like this: (use-fixtures :once fixture1 fixture2 ...) --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~--~~~~--~~--~--~---
new in duck-streams: with-out-writer / with-in-reader
Following a discussion from a few days ago, I've added two new macros to clojure.contrib.duck-streams: (defmacro with-out-writer Opens a writer on f, binds it to *out*, and evalutes body. [f body] `(with-open [stream# (writer ~f)] (binding [*out* stream#] ~...@body))) (defmacro with-in-reader Opens a PushbackReader on f, binds it to *in*, and evaluates body. [f body] `(with-open [stream# (PushbackReader. (reader ~f))] (binding [*in* stream#] ~...@body))) -Stuart Sierra --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~--~~~~--~~--~--~---
new contrib: with-ns macro
Hi folks, New lib in contrib: with-ns -- a library to temporarily switch namespaces at run-time. People request this occasionally, and I finally came up with a way to do it. The code is sneaky, and it relies on eval, but it works. Here's the doc: clojure.contrib.with-ns/with-ns ([ns body]) Macro Evaluates body in another namespace. ns is either a namespace object or a symbol. This makes it possible to define functions in namespaces other than the current one. - clojure.contrib.with-ns/with-temp-ns ([ body]) Macro Evaluates body in an anonymous namespace, which is then immediately removed. The temporary namespace will 'refer' clojure.core. -Stuart Sierra --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~--~~~~--~~--~--~---
Re: Request for improved error reporting
2009/3/29 Stephen C. Gilardi squee...@mac.com On Mar 28, 2009, at 10:31 PM, Glen Stampoultzis wrote: It wasn't really this specific problem that I wanted to point out but more to trigger a rethink of how errors are reported back to the user. I understand, but without specifying which Clojure you're using and giving an example of how it happened, it's hard to compare our results. Sorry when I said the latest released version of clojure I thought that would be enough to go on. I was using clojure_20090320.zip which matches your version. Here's an example that gives an error somewhat similar to the one I posted: (defn testing [a b] (print a b)) (testing) java.lang.NoSuchMethodError: java.lang.Class.getSimpleName()Ljava/lang/String; (testing.clj:0) [ and lots more stack trace ] Here's what I get with clojure_20090320 downloaded from: http://code.google.com/p/clojure/downloads/list % java -cp clojure.jar clojure.main Clojure user= (defn testing [a b] (print a b)) #'user/testing user= (testing) java.lang.IllegalArgumentException: Wrong number of args passed to: user$testing (NO_SOURCE_FILE:0) user= That's quite different from your result and I think more in line with what you're requesting. Are you able to reproduce this result using the Clojure version I referenced? --Steve The difference was that I wasn't running through the REPL. When I run through the REPL I get the same result as you. If you run the code from a file you get: C:\products\clojurejava -cp clojure.jar clojure.main test.clj java.lang.IllegalArgumentException: Wrong number of args passed to: user$testing (test.clj:0) at clojure.lang.Compiler.eval(Compiler.java:4533) at clojure.lang.Compiler.load(Compiler.java:4846) at clojure.lang.Compiler.loadFile(Compiler.java:4813) at clojure.main$load_script__5793.invoke(main.clj:206) at clojure.main$script_opt__5824.invoke(main.clj:258) at clojure.main$main__5848$fn__5850.invoke(main.clj:333) at clojure.main$main__5848.doInvoke(main.clj:328) at clojure.lang.RestFn.invoke(RestFn.java:413) at clojure.lang.Var.invoke(Var.java:346) at clojure.lang.AFn.applyToHelper(AFn.java:173) at clojure.lang.Var.applyTo(Var.java:463) at clojure.main.main(main.java:39) Caused by: java.lang.IllegalArgumentException: Wrong number of args passed to: user$testing at clojure.lang.AFn.throwArity(AFn.java:449) at clojure.lang.AFn.invoke(AFn.java:48) at user$eval__4.invoke(test.clj:2) at clojure.lang.Compiler.eval(Compiler.java:4522) ... 11 more I think part of my problem is that I'm thinking of it as a compile error when actually it's a runtime error. Even so most of the stack is unnecessary - would it be feasible (or even desirable) to strip the parts not relevant to the user? --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~--~~~~--~~--~--~---
Re: new in duck-streams: with-out-writer / with-in-reader
On Mar 29, 7:36 am, Stuart Sierra the.stuart.sie...@gmail.com wrote: Following a discussion from a few days ago, I've added two new macros to clojure.contrib.duck-streams: (defmacro with-out-writer Opens a writer on f, binds it to *out*, and evalutes body. [f body] `(with-open [stream# (writer ~f)] (binding [*out* stream#] �...@body))) (defmacro with-in-reader Opens a PushbackReader on f, binds it to *in*, and evaluates body. [f body] `(with-open [stream# (PushbackReader. (reader ~f))] (binding [*in* stream#] �...@body))) -Stuart Sierra This is very useful. Thank you :) --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~--~~~~--~~--~--~---
Re: oo
On Mar 28, 4:28 pm, David Nolen dnolen.li...@gmail.com wrote: On Sat, Mar 28, 2009 at 4:40 PM, mikel mev...@mac.com wrote: So, at minimum, to make a solid port, you need to add a function that can return a sensible type value for any input Enjoying the thread. Out of curiosity for which Clojure values is the return value of the type function undefined? Try this: (type (proxy [clojure.lang.IMeta clojure.lang.IRef][])) java.lang.UnsupportedOperationException: meta (NO_SOURCE_FILE:0) [Thrown class clojure.lang.Compiler$CompilerException] No doubt someone is going to point out that the proxy object I created there is useless; that's true, but beside the point. The point is that it's straightforward to create some value v for which (type v) is undefined. In order to make a Clojure-friendly version of CLOS, you need some concept of object type such that you can define a function that returns a sensible type for any value. The way that Dylan handled situations similar to Clojure's proxy objects was with objects called singletons; a singleton is an object that represents a specific value as a class. For example, (singleton 5) returns an object that is a class, but is also the integer 5. You can define methods that specialize on such objects. For example, below is an excerpt from the UI libraries of Apple's long- ago Bauhaus project. Notice the first line: (define-method build-form ((key (singleton label:)) The equivalent syntax in Clojure (if clojure had these mechanisms) would be: (define-method build-form [[key (singleton :label)] (There was no equivalent of defn in Dylan; there was only define- method, because all values were instances of Dylan classes, and in that environment a defn is no different from a define-method without value constraints. Consequently, all functions were polymorphic; all unsealed functions could be extended by adding new method definitions.) (define-method build-form ((key (singleton label:)) remaining-spec form current-x current-y layout-vector) (ignore key) (bind ((label-string (car remaining-spec)) (next (rest remaining-spec))) (add-feature-to-form (make label-text string: label-string top: current-y left: current-x style-array: $espy-10-bold-pointer) next form current-x current-y layout-vector))) --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups Clojure group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~--~~~~--~~--~--~---