Re: Feature idea: meta-macros
My suggestion is inline with other commenters: use binding. If that doesn't satisfy you, consider using or writing a preprocessor like m4. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: JSON lib of choice?
The c.c.json lib was rewritten in January by Stuart Sierra to incorporate the missing features present in Dan Larkin's lib, and make it faster. This was when it switched from c.c.j.read/write to c.c.json. I switched to c.c.json around that time, and I've been happy with it as a substitute. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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 Primitive data types (equal branch) - impact on optimized code.
Mark, I don't disagree with your message as a whole, but: Once you start using mutable arrays and type hinting every single variable, why aren't you just using Java? The argument I've heard is this: there are two ways to get a fast program in a slow-by-default language. The first is Python's way: write the whole thing in Python (high- level), find out the parts that are slow, then rewrite those in a different language (C). Now you need a C compiler, you need to build separately on each platform, and so on. The second is Common Lisp's way: write the whole thing in un-annotated CL (high-level), find out the parts that are slow, then add annotations or make representational changes (lists = vectors, alists = hash-maps) to allow the compiler to make them fast. The argument is that being able to use *the same language* to write anywhere on the spectrum from slow/succinct to fast/verbose is useful: no complex combined build system, no bridging between environments, iterative development, easier profiling, your code always works, etc. If I can take one little part of my Clojure program and make it ugly like Java to get it as fast as Java, it's better than having to actually _use_ Java in a heterogeneous project. -R -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Enhanced Primitive Support
user= (defn fac [n] (loop [n n r 1] (if (= n 1) r (recur (dec' n) (*' r n) NO_SOURCE_FILE:5 recur arg for primitive local: r is not matching primitive, had: Object, needed: long Auto-boxing loop arg: r #'user/fac user= (fac 40) 8159152832478977343456112695961158942720N Might I suggest that this message be augmented to include the recommended course of action, or at least a pointer to docs? I can easily imagine a stream of confused people a year or so from now wondering how they can either (a) get the recur arg to match the primitive local, or (b) get a non-primitive local. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Enhanced Primitive Support
I agree with Nicolas. An overflow says you did math that doesn't work with basic numbers and pretty much everybody coming to computers via any path may encounter that from time to time. It's basic stuff. There's a distinction between knowing that something can occur, and expecting to have to handle it in user code. (Particularly without something like checked exceptions to tell you about it.) If you're coming from Python, or Common Lisp, or any one of a hundred other languages, you know that numeric overflow can occur... and you expect your programming language to automatically promote on your behalf. math.factorial(50) + 1 304140932017133780436126081660647688443776415689605120001L We similarly expect our PL and OS stack to handle virtual memory paging, garbage collection, and so on, even though that's basic stuff that everyone knows. The question here is whether Clojure is a primitive language, where numbers are machine numbers by default, or a modern language, where getting primitive math might require input from the programmer, but by default all operations are promoting and conceal the limitations of the hardware. (The big trick is that there are limitations imposed by the JVM.) My personal feeling is that one should be able to write non-hinted code and have it work without exceptions for all input ranges, and that the compiler should (a) do static analysis to optimize code when enough info is available, and (b) provide rich compiler messages to allow hints when it's not. I am now firmly in the camp that would prefer performance by default and fewer surprises for folks new to Clojure. This is interesting. One set of folks considers non-machine-number performance to be surprising, and wants to avoid it. Another set of folks considers the possibility of arithmetic exceptions for certain combinations of input to be surprising, and wants to avoid them. Nobody likes surprises, but discounts the other folks' surprise as less important :) That's probably colored by my background where most of the languages I grew up with that shaped my experience gave you overflow exceptions from fact( someLargeNumber ) but they calculated fact( reasonableNumber ) very fast :) I'm used to languages where the compiler gives you both, and if it can't it can tell you why... http://www.franz.com/support/documentation/8.2/doc/compiler-explanations.htm#explain-1 ;Tgen1:Examined a call to +_2op with arguments: ;Targ2: symeval x type in fixnum range (integer 0 64) ;Tinf1: variable-information: lexical: ((type (integer 0 64))) ;Targ3: constant 1 type in fixnum range (integer 1 1) ;Tres1: which returns a value in fixnum range of type (integer 0 64) versus ;Call1:Generated a non-inline call to /_2op: ;Tgen1:Examined a call to /_2op with arguments: ;Targ2: symeval sum type in fixnum range (integer -536870912 536870911) ;Tinf1: variable-information: lexical: ((type (integer -536870912 536870911))) ;Targ3: constant 4096 type in fixnum range (integer 4096 4096) ;Tres1: which returns a value of type (rational * *) -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Enhanced Primitive Support
This imposes too high a burden on any programmer who cares about safety. Don't buy it. That's the whole point of BigInt contagion. If fact and foo are correctly written this will work. It only takes one library to screw up, and the whole stack falls down. Screwing up can occur because of omission (fact being written with a 1, not 1N, and not being tested with large inputs), or by design. This whole debate arose because people care about the speed of their numeric functions! The safety bignums (which make things slower) will be omitted for performance reasons, or by accident, and people won't obey the contract of the function… or won't be able to because of the complex interactions between libraries. I can't control where every value in my program goes. In Clojure as it stands now, those edge cases would see a small performance penalty as bignums occurred (and then it would go away if they got demoted!). After this change, a one-in-a-million collision of numbers and performance-oriented programming would throw an exception with no way to recover from higher up the stack. A programmer who really cares about safety would thus indeed have to shoulder a massive burden: either review and get complete test coverage over every library in their dependency stack, or ensure that no non-bignum can ever enter a library function. I guess that also means no strings, no file sizes, no URLs, no values which might get recombined… because any of those values could produce a non-bignum and enter an unsafe Clojure library function, causing an overflow with no possibility of continuing. (This ain't Common Lisp.) Having digested Rich's notes, pretty much the only thing that I disagree with is the lack of automatic bignum promotion/demotion. It seems like too much of a bad tradeoff, sacrificing one of Clojure's selling points for a little numeric performance. Thus far, Clojure has done pretty well in lexically scoping its please make this fast and unsafe bits — primitive calls, loop, transients. This would break that pattern. I wonder: is there's a middle ground, where primitives are automatic almost everywhere, but bignum promotion on overflow is still possible? -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Enhanced Primitive Support
I don't want to commit to a full-fledged response on this issue (yet), but: On the other hand, the mental burden for someone who wants BigInts in the new system is very low - you'll get a trivial to track exception. Assuming that I understand your implication (that ArithmeticExceptions are trivial to track): that might be true in Java, with checked exceptions, but it wouldn't be true in Clojure. If some operations overflow some of the time, you need thorough tests… and for all of the libraries you use to have thorough tests. It's not a small mental burden to constantly fear that any library call at all could suddenly overflow at any time. What are we, C programmers? Automatic type promotion is a good thing, if not without its quirks (map behavior being one of them). One of the fantastic things about Common Lisp is its rich numeric tower. That said, if we could have speed and safety… -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Enhanced Primitive Support
... which, I acknowledge, might be very hard work, possibly involving every such function having 2 polymorphic variants, one generic boxed form and one unboxed form, automatically selected and call-site-cached like OO dispatch. That's pretty much what Common Lisp compilers do. The compiler (or your own compiler macro, if you so choose) can examine the input forms and the compiler environment to decide what code to produce. The following is from Allegro Common Lisp, but all of the input is ANSI CL -- part of the spec. Observe how the compiler switches between different implementations of trivial addition as it gets a progressively looser or tighter bound on x. (I've elided some of the irrelevant preamble.) What would be nice is if Clojure and/or the JVM could produce safe code/bytecode that wouldn't overflow, but could also be JIT-optimized into unboxed primitive arithmetic for known input ranges. ;; Range known, optimizing for speed: assembly add instruction. cl-user(7): (disassemble (compile nil (lambda (x) (declare (type (integer 0 255) x) (optimize (speed 3))) (+ x 2 ... 15: 48 83 c7 10 addrdi,$16 19: f8 clc 20: 4c 8b 74 24 10 movq r14,[rsp+16] 25: c3 ret ;; We know that x is a fixnum: the arithmetic doesn't need a function call, but ;; the result will be a boxed bignum, because fixnum + 2 won't fit in a fixnum. ;; If this function were inlined elsewhere, the compiler might avoid that decision. cl-user(8): (disassemble (compile nil (lambda (x) (declare (type fixnum x) (optimize (speed 3))) (+ x 2 ... 21: 74 01 jz 24 23: 17 (pop ss); sys::trap-signal-hit 24: 48 c1 ff 03 sarrdi,$3 28: 49 c7 c5 02 00 movq r13,$2 00 00 35: 49 03 fd addq rdi,r13 38: 4c 8b ef movq r13,rdi 41: 49 d1 e5 sall r13,$1 44: 70 19 jo 71 46: 49 d1 e5 sall r13,$1 49: 70 14 jo 71 51: 49 d1 e5 sall r13,$1 54: 70 0f jo 71 56: 49 8b fd movq rdi,r13 59: f8 clc 60: 48 8d 64 24 78 leaq rsp,[rsp+120] 65: 4c 8b 74 24 10 movq r14,[rsp+16] 70: c3 ret 71: 41 ff 57 47 call *[r15+71]; sys::box-to-new-bignum 75: eb ef jmp 60 77: 90 nop ;; Nothing known: call to excl::+_2op, the two-arg addition function. cl-user(9): (disassemble (compile nil (lambda (x) (declare (optimize (speed 3))) (+ x 2 ... 21: 74 01 jz 24 23: 17 (pop ss); sys::trap-signal-hit 24: 40 f6 c7 07 testb dil,$7 28: 75 12 jnz 48 30: 48 83 c7 10 addrdi,$16 34: f8 clc 35: 70 1e jo 67 37: 48 8d 64 24 78 leaq rsp,[rsp+120] 42: 4c 8b 74 24 10 movq r14,[rsp+16] 47: c3 ret 48: 49 8b af 2f ff movq rbp,[r15-209]; excl::+_2op ff ff 55: 48 c7 c6 10 00 movq rsi,$16 ; 2 00 00 62: ff 53 d0 call *[rbx-48] ; sys::tramp-two 65: eb e2 jmp 37 67: 49 c7 c5 10 00 movq r13,$16 ; 2 00 00 74: 49 2b fd subq rdi,r13 77: eb e1 jmp 48 79: 90 nop -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: reacting to an article on clojure protocols, ruby monkey patching, and safety
The surface of the problem is reduced because of namespacing: two different fold methods (with different semantics) from two protocols won't clash. Plus if there are two extensions of the same protocol to the same type, they should be rather equivalent since they satisfies the same semantics. Incidentally, this is the difference between pre-web and post-web tools. Before the web, databases and identifiers would be age, or name; after the web we'd have http://foo.com/age;, or in Clojure com.foo/age. The former behaves as if it owns the entire world, and it's very likely to result in collisions; the latter is very unlikely. This issue of ambiguous identification is one of the problems that semantic web tools try to solve. The former, of course, is how Ruby works -- if you open the string class and add a 'frob' method, then it will clash with someone else's 'frob' method. The latter is how Clojure works, because protocols are namespaced, and good namespaces are reverse domains or otherwise controlled. If you use com.foo.bar/frob, you're claiming to obey the contract of that particular frob operation, so even in the situation where collision occurs, both implementations should at least share a conception of what 'frobbing' means. I think one must only extend a protocol to a type if he owns either the type or the protocol. That sounds like a reasonable rule of thumb, though I'd change it to publicly extend, or add if you want to be safe :) -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Understanding sequence abstraction
1. In case coll is a LazySeq why does (seq coll) realize its first element? I thought seq just did a type conversion and all of list, vector .. etc implemented Seqable or something. Because seq is defined as returning nil for an empty sequence. The only way to find that out for a lazy sequence is to realize the first element. 2. Why is there no other way to determine an empty coll except (not (seq coll)). user= (empty? []) true -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: API for posting multipart/form-data
Anyone know of a Clojure library (or wrapper) for posting HTTP multipart/form-data? Do you mean submitting or receiving? If you mean submitting, clj-apache-http will allow you to do it. http://github.com/rnewman/clj-apache-http Simply create any Apache HttpEntity and pass it as the value of :body. http://james.apache.org/mime4j/apidocs/org/apache/james/mime4j/message/Multipart.html?is-external=true http://hc.apache.org/httpcomponents-client/httpmime/apidocs/org/apache/http/entity/mime/HttpMultipart.html For example: (require ['com.twinql.clojure.http :as 'http]) (import 'org.apache.http.entity.mime.MultipartEntity 'org.apache.http.entity.mime.content.StringBody 'org.apache.james.mime4j.message.BodyPart) (let [body (doto (MultipartEntity.) (.addPart partone (StringBody. Hello, world)))] (http/post http://foo.com/; :body body)) -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: last-var-wins: a simple way to ease upgrade pain
(+ today (- 14 remind-prior)) = 2 weeks from today - a fixed remind before days = a date when I am going to be reminded for an event 2 weeks from today I'm deeply suspicious of such a behaviour. Why would + on a date mean adding days? Frink (as one example) resolves this through unit tracking. Examples from http://futureboy.homeip.net/frinkdocs/#DateTimeHandling: #1969-08-19 16:54 Mountain# + 1 billion seconds AD 2001-04-27 06:40:40.000 PM (Fri) Mountain Daylight Time #2002-12-25# - now[] - days 105.70975056709 -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: deftype and final classes
What are you going to do about: default public constructor? The JAX-WS tools don't really care if javac generates a default constructor or if Clojure does. The deftype constructor with no fields defined is: public com.example.FooBarService(); which -- assuming it calls super() and initializes any instance vars -- is identical to the constructor that javac would produce. wsgen runs without complaint once the class is declared non-final, so I assume it's happy with what Clojure produces. Remember that deftype is not primarily an interop feature. It's not going to become Java-in-parens, as that doesn't add much value over Java for the significant complexity it introduces into Clojure. Understood. While non-final seems small, I'm concerned that accommodating various interop requirements (many of which are horrid) will complicate deftype, and the lives of its users. I would personally draw that line at anything which can't be defined simply in an option, or which breaks the contract between a def'ed type and the rest of Clojure. For example, if deftype required a finalizer to work with the Clojure runtime, I'd give up. Similarly, if some other part of Clojure demanded that all def'ed types must be implemented as final classes, I'd settle for gen-class. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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
Example JAX-WS server code using annotation support
I just spent a little time figuring this out, so I figured I'd share. http://gist.github.com/381129 This example shows how to hang annotations onto Clojure code to replicate the equivalent Java web service code produced by NetBeans. It includes exported parameter names, types, and operationNames. The correct classes seem to be generated, though I confess I haven't tried loading this into a container yet. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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
deftype and final classes
Further to IRC conversations: I'm attempting to generate a JAX-WS service using Clojure. The main stumbling block was annotations; that's been removed, so I gave it a shot using deftype. My first strike works code-wise, so I sent it to the list earlier today. When it comes to actually integrating the output into the Java world, though, things get hairy. JAX-WS has a bunch of demands on classes in order for its tools (such as wsgen) to accept them: http://java.sun.com/webservices/docs/2.0/tutorial/doc/JAXWS3.html --- JAX-WS endpoints must follow these requirements: * The implementing class must be annotated with either the javax.jws.WebService or javax.jws.WebServiceProvider annotation. * The implementing class may explicitly reference an SEI through the endpointInterface element of the @WebService annotation, but is not required to do so. If no endpointInterface is not specified in @WebService, an SEI is implicitly defined for the implementing class. * The business methods of the implementing class must be public, and must not be declared static or final. * Business methods that are exposed to web service clients must be annotated with javax.jws.WebMethod. * Business methods that are exposed to web service clients must have JAX-B-compatible parameters and return types. See Default Data Type Bindings. * The implementing class must not be declared final and must not be abstract. * The implementing class must have a default public constructor. * The implementing class must not define the finalize method. * The implementing class may use the javax.annotation.PostConstruct or javax.annotation.PreDestroy annotations on its methods for lifecycle event callbacks. The @PostConstruct method is called by the container before the implementing class begins responding to web service clients. The @PreDestroy method is called by the container before the endpoint is removed from operation. --- The classes generated by deftype are final; the javap output is --- public final class com.example.FooBarService extends java.lang.Object implements com.example.FooBarInterface{ public static {}; public com.example.FooBarService(); public java.lang.String createCustomer(java.lang.String, java.lang.String, java.lang.String); } --- That doesn't make JAX-WS's tools happy: --- com.sun.tools.ws.processor.modeler.ModelerException: modeler error: Classes annotated with @javax.jws.WebService must not be final. --- Digging into the compiler, it looks like individual fields can be made non-final by flagging them as mutable. The class emitter in `compile`, however, always passes ACC_PUBLIC + ACC_SUPER + ACC_FINAL to the ClassVisitor.visit method... so classes produced in this way are always final. From a purity perspective, this is nice: Clojure prohibits implementation inheritance because it's a Bad Idea®. However, this hampers interop (I don't *want* to do implementation inheritance, but JAX-WS demands non-final classes!), and the mutable/volatile options for fields seem to suggest that getting hands dirty is acceptable at the level of deftype… and thus having some optional way to produce non- final classes might be a reasonable feature to add. Chouser suggested gen-class, which generates non-final classes; that's my next fallback, once annotation support for gen-class gets integrated. However, if this isn't an intentional and inflexible limitation on deftype, I thought I'd investigate removing it. So I spent a little time with the compiler, producing three patches: * Pass options through to deftype emission (they never made it past deftype in the current code). * Propagate class accessibility flags throughout build/compile (parameterizing the ACC_FINAL/ACC_PUBLIC/ACC_SUPER flags). * Allow (and check for) :non-final as a boolean option for deftype. The test suite runs without problems, and I've verified that adding `:non-final true` generates a non-final class (and the reverse). With this change I'm able to run wsgen against a jar built by Leiningen, containing no Java code, and get WSDL as output. Pretty neat, no? I've pushed these to my GitHub fork (rather than sending patches to the list): http://github.com/rnewman/clojure/tree/deftype-non-final Opinions, thoughts, critiques, you're insanes, etc. welcome. Thanks, -Richard -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Datatypes and Protocols update
Neither of those attributes reveal information about the implementation of the objects in question. They both reveal information about the state that some client could find useful. They are both values that, if not directly available from the object should be calculated by the object, as calculating the value requires knowledge about the implementation. This approach still isn't 'good' OO -- it might not leak implementation details, but it supports asking, not telling. http://pragprog.com/articles/tell-dont-ask That is, you should endeavor to tell objects what you want them to do; do not ask them questions about their state, make a decision, and then tell them what to do. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Annotations
I've started adding some support for Java annotations, as of this commit: Fantastic! I'm just about to do some JAX-WS stuff (which requires annotations), so this is a welcome change. The syntax looks no worse than Java's, so no comment on that... -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: questions about clojure's core library organization
Something like the 'for' macro (if it is thought of as a non-general monad) can be implemented in terms of reduce. Is there a reason this isn't so? I can think of two: * filter and map are lazy. Implementing every? and some? in those terms would needlessly introduce lazy sequences to the mix. That introduces a tiny amount of additional cost, and... * core does some ugly things (redefinitions, avoiding the use of some functions because they haven't been defined yet, writing things in Java, etc. etc.) for the sake of speed, because core is used *everywhere*. It's not necessarily a manual for good Clojure style unless you understand which constraints apply. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Set as function
Why this behavior? It's useful: e.g., you can use a set as a filter. user= (filter #{2 3 4 5} (range 1 10)) (2 3 4 5) If you want your alternative, use contains?: user= (contains? #{true false} false) true -- 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 Note that posts from new members are moderated - please be patient with your first post. 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 To unsubscribe, reply using remove me as the subject.
Re: Set as function
filter works just as well with a function that returns true and false, so that's not a particularly good example. Heh, that's true. Should have re-read :) -- 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 Note that posts from new members are moderated - please be patient with your first post. 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 To unsubscribe, reply using remove me as the subject.
Re: formatting hex string
ur= (map #(Integer/parseInt % 16) [ff43 0032]) (65347 50) ...that yields, not shorts. At the risk of diverging from the question: why are you concerned with the specific type of the number? You realize that Java doesn't allocate less memory for a short than for an int, right? The only time it becomes more efficient is when you have a primitive array, in which case the JVM might pack the values. This is not a primitive array. On a related note: if I have the symbol for a type, like short or int or byte, is there a way to ask Clojure what size word that represents? In Java, byte/char/short/int are all represented the same: 32 bits. Long is 64. If you mean how many octets would this take to represent in C: (def word-size {'short 2 'byte 1 'int 4 'long 8}) user= (word-size 'short) 2 but that's hardly a correct answer in the broadest scope. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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 To unsubscribe, reply using remove me as the subject.
Re: copying structures
This may be really basic. So much so that it's hard to find on the internet, but is there something like a copy constructor in clojure, where I can copy everything in a structure except one or two keys? Maybe something like struct-map, but fills in the other variables not supplied by another data structure. There's no need for copying with Clojure's native data structures. Clojure data structures are persistent: for example, if you dissoc a key from a map, you get a new map with the same contents as the original minus the dissociated key. The original map is unchanged. The new map safely shares structure with the original. This is both efficient and safe. E.g., user= (def aaa {:foo 1 :bar 2 :baz 3}) #'user/aaa user= (dissoc aaa :foo :baz) {:bar 2} user= aaa {:foo 1, :bar 2, :baz 3} If you want to draw values from two maps, use merge: user= (merge {:foo 0 :bar 0 :baz 0} (dissoc aaa :foo :baz)) {:foo 0, :bar 2, :baz 0} -- 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 Note that posts from new members are moderated - please be patient with your first post. 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 To unsubscribe from this group, send email to clojure+unsubscribegooglegroups.com or reply to this email with the words REMOVE ME as the subject.
Re: copying structures
Is there a shorter way to do this? See my earlier message. dissoc and assoc will do what you want. (def brother {:name Gary :address ... :mother Mary :father John}) (def sister (assoc brother :name Cindy)) user= sister {:name Cindy, :address ..., :mother Mary, :father John} While I'm on the subject, what is the difference between a structure and a hash? Are there performance implications? Why wouldn't I just use a hash if structs can hold new values anyway? When should I use one over the other? A struct-map is strictly a performance optimization, with one additional constraint (that the required keys cannot be removed from the struct: if you try, you'll get an error). In every other respect it behaves just like any other map. There are only two reasons to use struct-maps: if you've profiled and need the tiny performance improvement (struct-maps store their required keys in an internal array, which is sometimes faster); or if you feel that struct-maps offer some documentation advantage for your code. struct-maps are not Clojure's equivalent of objects. Use maps unless you have a clear reason to do otherwise. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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 To unsubscribe from this group, send email to clojure+unsubscribegooglegroups.com or reply to this email with the words REMOVE ME as the subject.
Re: copying structures
Is this the common way to do it? (def sister (assoc brother :name Cindy)) If you want to change the value of one key in a map, yes. (In this example it looks weird, of course.) If you want to create a new map by taking only some values from another map: user= (def sister (assoc (select-keys brother [:father :mother]) :name Mandy)) #'user/sister user= sister {:name Mandy, :mother Mary, :father John} Reading up more on structs, it seems they have base keys that can't be dissoc. Is that the main difference then between it and a hash? Yes. The base keys are reserved as an array, which provides a slight performance enhancement in some situations (no tree-walking). If you have no need for that tiny performance enhancement, you can ignore struct-maps altogether. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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 To unsubscribe from this group, send email to clojure+unsubscribegooglegroups.com or reply to this email with the words REMOVE ME as the subject.
Re: converting long string to number
Of course, it might also pose a bit of a security threat: user (read-string #=(println \I OWN YOU NOW!\)) I OWN YOU NOW! nil :) user= (binding [*read-eval* false] (read-string #=(println \I OWN YOU NOW!\))) java.lang.RuntimeException: java.lang.Exception: EvalReader not allowed when *read-eval* is false. (NO_SOURCE_FILE:0) -- 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 Note that posts from new members are moderated - please be patient with your first post. 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 To unsubscribe from this group, send email to clojure+unsubscribegooglegroups.com or reply to this email with the words REMOVE ME as the subject.
Re: converting long string to number
In those hills yonder in the lands of Common Lisp, it's usually considered good practice to blast the entire read table save for what you need when you deal with untrusted data. Barring that, a better option might be a more modular reader: read-number, read-symbol, etc. Clojure doesn't have a user-programmable reader, so much of the readtable shenanigans we use in CL don't apply. But yes, specific readers would be neat. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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 To unsubscribe from this group, send email to clojure+unsubscribegooglegroups.com or reply to this email with the words REMOVE ME as the subject.
Re: Why I have chosen not to employ clojure
To be successful however Clojure needs to adopt 'mainstream' values - introduce just one 'different' thing i.e. the language, rather than expecting people to adopt both the language, and a different development environment / toolchain e.g. leiningen etc (which IMO is classic NIH). I think that depends on your definition of successful. If you think popular with mainstream Java developers is the definition of success, then yes: not scaring those poor folks is important. I don't count that as success -- I call that popularity. I'd much rather have Clojure make me personally productive (and that means Swank, standalone REPLs, introspective debugging, etc.) than somehow feel validated because lots of faceless Java folks can get past some environment issue, only to reach the point of being scared away by the parentheses and immutable functional programming. Ultimately, though, it all comes down to here are some jars. If a Java developer can't figure that much out, they're probably not going to get very far regardless. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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 To unsubscribe from this group, send email to clojure+unsubscribegooglegroups.com or reply to this email with the words REMOVE ME as the subject.
Re: Translation from Common Lisp 1
But using symbols for something like this is a bit contrived anyway. Maybe, but I've seen it in other Common Lisp books/tutorials before. e.g. I'm sure PAIP was one of them. Part of the motivation is that CL symbols always compare with EQ and EQL, whilst strings are not required to do so: cl-user(9): (eq (concatenate 'string foo bar) foobar) nil This means you can use nice constructs such as CASE with symbols, but you need to roll your own using string-equal or string= to handle strings. (Using symbols also saves you typing all those double-quote characters, as well as saving memory and computation during comparison: symbols are interned, unlike strings.) In Clojure (thanks to Java's immutable interned strings) strings compare efficiently with = just like everything else, so there's less motivation. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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 To unsubscribe from this group, send email to clojure+unsubscribegooglegroups.com or reply to this email with the words REMOVE ME as the subject.
Re: help with infinite loop: break and examine stack? dynamic tracing? circular lists?
An alternative: Is there a way to watch my running Clojure program without breaking it, that is to observe the recent call history (of my own definitions, either all of them or specifically marked ones) from outside the process? If you send a SIGQUIT to the java process, it will print the thread info (including call stack) for each thread to stdout. You can also try attaching a Java debugger. They should all work for this purpose, if not showing locals etc. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: help with infinite loop: break and examine stack? dynamic tracing? circular lists?
It'd still be even nicer to be able to get some info without quitting, but this is definitely an improvement! The JVM shouldn't quit when it gets a SIGQUIT. That's just the signal name. You might find this useful: http://www.unixville.com/~moazam/stories/2004/05/18/debuggingHangsInTheJvm.html -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: A Tour of Enlive
I just finished up a fairly involved tour of Enlive. Great stuff, thank you for sharing. If I have any comments as I walk through, I'll send them along. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Leiningen, Clojure and libraries: what am I missing?
I'm confused. Why do we need symlinks or copies at all? Why can't we just tell clojure where it's supposed to find a given projects dependencies? I'm sure the answer involves some mumbo-jumbo about classpath and what not, but surely there has to be a better alternative than whatever maven/leiningen are currently doing. Not if we want to precompile code and create an überjar, or otherwise integrate with Java. Ultimately, tools expect a pile of jars listed in the classpath. Management of those jars is easier if they're (actually or virtually) in one place. I'm from a CL background too, and I do long for the days of the continuum from a load script through to ASDF and friends, but at some point it makes sense to give up and do things The Java Way. Even simple things like log4j.properties are looked up on… you guessed it: the classpath. It's not a battle that's worth fighting. On a related note, why is the build system the cool kids seem to be using (leiningen) controlled by a bunch of shell scripts? Surely things like compiling .clj source files and making jars should be operations one can drive from the clojure repl, no? It's a shell script wrapping a bunch of Clojure code. I'm sure you could use Leiningen as a library: each task is simply a function which calls out to Maven or Lancet. Oh, and on a related note, I hate being forced into the src, test, lib heirarchy... Let me put my files where I want them to go. Whatever happened to the lancet build system from Stuart Holloway's book? That seemed to make sense to me. That's convention over configuration (though you can put alternatives in the Leiningen project.clj file). It's one of those things where it's easier to go with the flow, I'm afraid. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: quote versus backquote
Is there a good reason for this behavior? What is the rationale behind it? Read this. http://clojure.org/reader#syntax-quote -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Leiningen, Clojure and libraries: what am I missing?
What benefit does this have aside from a tiny saving in disk space? Not that tiny when you multiply it across the dozens of projects on your hard drive. repos $ du -hc $(ls */lib/*.jar) | fgrep total 291Mtotal Add to that the size of the Maven repo itself. Symlinks are nice. * you can tarball your project directory, rsync it another machine or whatever and everything you need will be right there. No need to worry about redownloading anything or copying your local maven cache around. Unix is great. man tar: -h, --dereference don't dump symlinks; dump the files they point to -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Leiningen, Clojure and libraries: what am I missing?
repos $ du -hc $(ls */lib/*.jar) | fgrep total 291Mtotal Cost (on standard disks): 5 cents. Sorry, that's tiny. It's even less than 0.5% of the small SSD I have in my laptop. Seriously, this is just premature optimization. You're seriously fine with every single Leiningen-based project spitting a redundant copy of Clojure, contrib, and whatever other dependencies it needs onto disk, and doing so every time it picks up a new snapshot? That every tiny library you pull off GitHub grabs another few dozen MB, rather than a few dozen KB? 290MB is only tiny if you have an empty disk. 290MB here, 290MB there, and suddenly the 13GB free on my 180GB laptop disk starts looking mighty cramped. I have a lot of stuff I'd rather store on that disk than 290MB of redundant jar copies. Those hundreds of megs get backed up, scanned, indexed, defragmented, yadda yadda. What a waste. You might also be overlooking disk caching, paging, JVM memory sharing, and other performance effects from having multiple instances of the same jars in memory. I know that the Mac JVM does some tricks to share memory in this way. Furthermore, it's slower to copy 28MB of jars than it is to symlink them: $ time cp -R lib /tmp/foo real0m2.981s user0m0.007s sys 0m0.152s ... surprise disk slowdown! All the nonsense of looking up snapshots, checking deps against the Maven repo, etc. already takes so much time that I dislike using Leiningen. Anything to bring that down by a few hundred milliseconds and a few fewer disk head slaps would be nice. There is no engineering reason to blindly copy jars into lib/. Hard links, symlinks, or computed classpaths are all better solutions in every single way. Premature optimization is the act of expending significant time addressing a performance problem prior to measurement, typically allowing unmeasured performance concerns to affect system design. Using symlinks instead of copying would not be a significant amount of work, doesn't affect the overall design, and we're hardly flying blind. You're using the wrong phrase. Here's a different Knuth quote: In established engineering disciplines a 12 % improvement, easily obtained, is never considered marginal and I believe the same viewpoint should prevail in software engineering I'd call this a decent improvement, and it's certainly easily obtained. Whatever happened to engineers building a decent solution out of a sense of pride, or even making the most basic half-assed attempt to conserve resources? Sometimes I despair. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Clojure Implementation issues that may affect performance?
I suspect that on recursion If you use plain function-calling recursion, yes. If you use (loop ... recur...) then (IIRC) locals are not boxed (as well as saving stack). Also bear in mind that JIT will come into play here; after a few tens of thousands of arithmetic ops, the common path will be nearly free. Don't call something slow without measuring it. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: monkeypatching in clojure
Yeah I'm not talking about OO vs FP but about the function-centric approach that Lisps and languages like Haskell take as opposed to the object, or noun-centric approach of languages like Java or Ruby. Interesting reading from 2006: http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Some basic guidance to designing functional vs. state parts of app
For a single value there seems to be little reason to adopt refs, though I've often wondered why Stuart Halloway's book gives an example updating a single ref of messages for a chat application. I seem to recall atoms being the last reference type to be introduced. They might not have existed when Stuart was writing. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: newbie question: Please help me stop creating constructors
I'd like to note that if you do this, you might just as well use the - function directly. Of course; this was merely for the sake of illustration. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: newbie question: Please help me stop creating constructors
but complexity of such expressions quickly grows as dependencies between variables become more complex. Is there any technique/framework for handling such calculations automatically? I have a vague impression that this is what logic programming languages are about. How would one implement such calculations in Clojure? As Johnny mentioned: this is a solver. Doing it in Clojure means writing something rather more complicated than a simple calculator! Clojure is not a logic programming language. You might find a cell/dataflow framework useful, which essentially gives you spreadsheet-like dataflow: http://richhickey.github.com/clojure-contrib/dataflow-api.html best introduced in its original Common Lisp form: http://smuglispweeny.blogspot.com/2008/02/cells-manifesto.html but you'll still have to do some manual decision-making. (Just like in a spreadsheet, you have to write the formulae...) You might also (depending on how things fall out) find some kind of table-based or multimethod-based approach to be adequate (e.g., making two different kinds of `sell` evaluation based on whether some value is nil). That will reduce the number of explicit branches in your code. If neither of those helps, then your best bet is to spend a little time with, say, Mathematica, Excel, and Prolog (or one of its successors). Those might well be better systems for handling this kind of web of dependencies. If you want a Lisp syntax for Prolog, try Allegro Common Lisp. http://www.franz.com/products/prolog/index.lhtml -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: bug: clojure.contrib.json should not default to use keywords.
Actually, HTTP headers are case-insensitive, so you can't really trust a regular map of keywords for all purposes. You'd have to reify a maplike construct (maybe a clojure.lang.IAssociative?) to take care of case differences. No idea if ring or compojure does this already yet. I don't see why you'd preserve case when keywordifying headers. After all, they're case-insensitive. I believe the stable versions of Compojure/Ring downcase all headers before keywordifying. The bleeding-edge Ring gives you options: the httpcore adapter does this: headers (reduce (fn [header-map #^Header header] (assoc header-map (- header .getName lower-case) (.getValue header))) {} (seq (.getAllHeaders request))) giving you a lower-case string map. You can also use Jetty, which I believe does things case-insensitively. There is IIRC middleware to do keywordifying. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: difference between if/when
hmm...I don't understand why clojure when and if simultaneously? What is the diffirences between them and when I should use one instead another one? Disregarding all of the practical benefits (such as an implicit do): languages often incorporate apparently redundant constructs because one of the roles of a language is to communicate your higher-level intent. Using (when (foo) (bar) (baz)) instead of (if (foo) (do (bar) (baz))) communicates some subtle distinctions to other programmers, despite their equivalence to the compiler: you're telling other humans that you didn't accidentally omit the 'else' clause; that you don't expect any code to run if the condition is false; that you're intentionally returning nil for false; that you're probably doing something with side-effects. There are more subtle clues that you'll pick up in certain people's styles, too -- I'm sure my use of when has a very different pattern to a Java guy's, colored by my Common Lisp experience. It would be a pretty dull programming language that doesn't allow you the leeway to express yourself. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: difference between if/when
I'm still undecided whether to shake this habit: , | (defmacro unless [pred body] | `(when-not ~pred ~...@body)) ` Heh. I still think that unless is a better name than when-not, but I've migrated pretty easily. This is an interesting point, though -- does unless communicate something slightly different to* when not, despite being functionally identical? And is the distinction important enough to justify a move towards a confusing Rubyesque undergrowth of equivalent syntactic sugar? Probably not, although `unless` is really no different to `when`: they both eventually expand into `if` forms. I'm not entirely sure where the line should be drawn, or why I draw it where I do... Incidentally, I initially didn't know about `when-not` -- I figured that `unless` had simply been omitted -- so I defined: (defmacro unless [pred body] `(when (not ~pred) ~...@body)) I was soon corrected :) -R * Read as than if you grew up with American English grammatical structures! Ah, language. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: bug: clojure.contrib.json should not default to use keywords.
For an example outside of JSON: recently Compojure changed how it works so the HTTP request properties are all converted to keywords by default. I can see the appeal, but now anyone using Compojure has the increased incidental complexity of possible keyword violations. Imagine if you were integrating with PayPal or some system that had HTTP parameters with characters that were not allowed by the Clojure spec. I really don't want to worry about such things when creating software with Clojure. Per RFC2616, HTTP headers are named by tokens: token = 1*any CHAR except CTLs or separators CHAR = any US-ASCII character (octets 0 - 127) CTL= any US-ASCII control character (octets 0 - 31) and DEL (127) separators = ( | ) | | | @ | , | ; | : | \ | | / | [ | ] | ? | = | { | } | SP | HT As far as I can see, all valid HTTP headers are thus valid Clojure keywords. You don't have to worry. -R -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: newbie question: Please help me stop creating constructors
So I rewrote the whole kit and kaboodle. My understanding of your mail led me to take the approach of defining functions who take as arguments the invariant values and who output functions that take variant values. For example: I'm not sure how much functional programming experience you have, but you've essentially discovered a kind of currying. http://en.wikipedia.org/wiki/Currying That is, you're taking a function house-sale-profit, in terms of house- sales-price (a function), house-sale-expenses (a function), and m, and fixing the first two values, returning a function in terms of m. This is seamless in Haskell; less so in Clojure. See the built-in function `partial`. When you wrote (defn house-sale-profit [house-sales-price house-sale-expenses] (fn [m] (- (house-sales-price m) (house-sale-expenses m and used it like this: (let [... house-sale-profit-fn (house-sale-profit house-sales-price house-sale-expenses) ...] ...) you could just as easily have written: (defn house-sale-profit [house-sales-price house-sale-expenses m] (- (house-sales-price m) (house-sale-expenses m))) and used it like this: (let [... house-sale-profit-fn (partial house-sale-profit house-sales- price house-sale-expenses) ...] ...) This makes house-sale-profit a perfectly normal function, but still allows you to partially evaluate it to yield a closure. In this example both house-sales-price and house-sale-expenses are actually themselves functions which I would have had to have called previously to get their instance functions and passed in as arguments. By doing this you're pretty much writing your own interpreter, as you figured out :) So is this the way you would approach this problem in Clojure? No. (However, consider that I'm as likely to be wrong as anybody else, and also that you're learning a ton by trying different approaches!) I would do things much more simply: rather than (to take your example) defining house-sale-profit in terms of two functions and a month value, which is threaded into those functions (providing opportunity for breakage should the signature of, say, house-sales-price change), I would simply *define house-sale-profit in terms of the sales price and expenses*. Rely on the price and the expenses having been calculated outside the function. No nonsense with throw-if-in-seq and all the other complicated machinery you have built. (defn house-sale-profit [house-sales-price house-sale-expenses] (- house-sales-price house-sale-expenses)) This is the literal definition of profit; you can write tests for this with just two numbers. If your expenses don't care about a number of months, or they care about something else, then just pass in a different value -- no futzing with functions. It's more efficient, too -- no anonymous functions. For a single invocation you're only using one value of m, with one house sales price, and one set of expenses. Just put them in the let! (let [m from the user price ... expenses ... profit (house-sale-profit price expenses) ...] ...) I've done this for some of your functions: http://twinql.com/tmp/rent.clj I haven't tried actually using it to compute anything, but it should give you an idea of the style I'd use. I would guess that the whole program, neatly laid out and commented, should come to only a couple hundred lines. Each individual function is trivially testable and reusable, as is every composition of functions that goes into computing the final answer. If you want to be neater, split `sell-calculator` into two or more functions; perhaps one which walks through the rent calculation, and another which walks through the house sale calculation. That way each individual function remains short and sweet. Note that I still curry some functions (e.g., inflate), and if I bothered to implement the agent fees (which are inflation-linked) I might do it by passing in that curried `inflate` function. (Then again, I might not, if I can phrase them in terms of constant values which are computed elsewhere.) Most of the intermediate values are simply computed directly. Note also that, if you wished, you could completely eliminate the `let` form, turning this whole calculation into a single (slightly redundant) tree. I don't advocate that as particularly good style, but it's possible. Ultimately, all you're doing here is writing a set of functions and combining them together to produce an answer: a simple matter of traditional programming. It's not rocket surgery (as they say nowadays), and so any solution which requires you to write code to detect recursive calls, look up function names at runtime, manage a huge intermediate map of results, etc. is probably a sign that you're over-engineering things. I would have used almost the
Re: browsing clojure source code
Can anyone suggest how best to browse the source code for clojure? I've downloaded the clojure-read-only tree and would like to bounce around in it using something like find-tag. How does one create an emacs tags file for java and clojure, or, how does one load it into eclipse so that eclipse groks where everything is? This is how I generate an Emacs tag file using Exuberant Ctags: /opt/local/bin/ctags -e -f $OUTFILE -R --language-force=lisp $DIRS -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Need advice on best concurrency model
I'd be very thankful if I could get some advice here, sicne I am running out of ideas. You might be doing something wrong with the way you're arranging refs. I'll let others comment on that. One observation, though: parallelization doesn't always help. pmap runs your tasks on several threads. If your tasks are compute-bound and modifying a shared resource, you'll probably see a net slowdown thanks to coordination overhead, cache trampling, and contention. Imagine the worst case, where you have 1 or 2 processors (and thus pmap uses three or four threads), and each of the four threads takes a turn, contends for the same ref, maybe swaps out, makes a conflicting change and causes a transaction rerun, swaps out... Running serially removes both the risk of contention and the coordination overhead. In general: use pmap if you have a lot of processors that you want to use, or you're doing tasks that spend a lot of time waiting around (e.g., web crawling). For pure computation on small datasets and desktop quantities of processors -- like munging game state -- it's probably not worthwhile. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: newbie question: Please help me stop creating constructors
I have to think that's preferable to submitting 30+ arguments to rent and sell. Or were you suggesting a different approach? The different approach only works with a different approach :) The way you've structured run-calculator, using the map is best, because 30 arguments is crazy. Your need to pass 30 arguments to rent and sell because they need to obtain or compute all of their intermediate values. You have a tree, with rent and sell doing all the work. The alternative approach is to make your functions take the intermediate values as arguments explicitly, and define those functions much like your equations. You then bind the intermediate values in a let... perhaps best shown by example. Instead of (defn house-depreciation The amount of depreciation that can be claimed on Federal Income Taxes in year y [y args] {:pre [(valid-year? y args)]} (cond ( y 27) 0 ( y 27) (/ (house-sales-price 0 args) 27.5) (= y 27) (* 0.5 (/ (house-sales-price 0 args) 27.5 you would write (defn house-depreciation The amount of depreciation that can be claimed on Federal Income Taxes in year y [y house-sale-price] {:pre [(valid-year? y args)]} (cond ( y 27) 0 ( y 27) (/ house-sale-price 27.5) (= y 27) (* 0.5 (/ house-sale-price 27.5 This transformation applies to all of your functions, so even rent and sell get defined in terms of their intermediate values, just as I showed in a much earlier email. Your calculator would become (defn run-calculator [args] (let [... house-sale-price (some-fn ... some-arg) ... house-depreciation (house-depreciation y house-sale-price) ... sell-value (sell house-sale-profit-0 rmoc mib) ...] (- rent sell))) This way your individual functions become really simple, expressed in terms of their direct named inputs and outputs only, just like your PDF's equations. Your calculator function becomes the place where the web of interconnected values is realized through a sequence of intermediate values. You can easily test each individual function, just as you can now, only without the overhead and syntax of those extra maps (which carry a ton of extra values and obscure what's happening). Individual functions are less likely to recompute redundant values (I'm sure rent and sell both involve some common terms), and that avoidance doesn't involve jamming intermediate values into the argument map. More interestingly, this means you can build calculators for different things (maybe comparing the tax advantages of different mortgages and depreciation tricks...) by using the same functions. I don't know if that's possible with the map approach as you've written it. What you've done with the argument map approach is essentially to use a map as an object: the map is a bunch of fields, your derived-args function is a constructor (which sets up the derived members), and your individual functions are methods on that object. It's OO with a mask. Now, OO is sometimes the right way to do things, but if you really want to see whether a more functional approach has advantages in this situation, you should consider whether you can invert things a little. Just a thought. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: newbie question: Please help me stop creating constructors
Richard Newman has with utmost patience (THANK YOU!), I believe, been trying to gently beat into my head from the start. No problem. Happy to help. Richard, your mails were extremely clear (and at this point I've read them all at least 2 or 3 times) but my head was so far away from the problem space that I needed a sufficient amount of beating before I could finally even begin to grok anything. It took me forever to get over the idea that I needed global variables. It was a stupid idee fixe on my part. These things take time! Props for not giving up in disgust :) I just took a piece of my code and re-worked it and made it available at http://www.goland.org/rent_or_sell_refactor.clj. Looks pretty good to me. I like your use of preconditions and the number of tests. I think your indentation is a little deep (I go for two spaces, myself), and I never use :Capital keywords, but otherwise great. You might be interested in the `are` macro to make your test code simpler: user= (doc are) - clojure.test/are ([argv expr args]) Macro Checks multiple assertions with a template expression. See clojure.template/do-template for an explanation of templates. Example: (are [x y] (= x y) 2 (+ 1 1) 4 (* 2 2)) Expands to: (do (is (= 2 (+ 1 1))) (is (= 4 (* 2 2 #2 - I created a function called derived-args. It takes as input a map that is to contain all the arguments provided by the user. It then adds to that map all the derived values. This means that the derived values get calculated exactly one time. It is the output of derived- args that will be put at the very top of the function chain and passed on down. That seems like a reasonable approach. Does http://www.goland.org/rent_or_sell_refactor.clj work more or less the way y'all have been suggesting? In other words have I finally created something that is heading in the 'right' direction? I realize you can't properly judge it until I'm done but I wanted to find out if I was roughly heading in the right direction. Pretty much! One suggestion: Rather than having two phases of derived args, and calling functions with arguments like: (total-house-depreciation args-and-mib) I'd save that step and adjust total-house-depreciation, year-sold, etc. to take an additional months-in-business argument: (defn total-house-depreciation The total amount of depreciation on the rental property taken over the period we were in business [args months-in-business] ...) Then you can change your derived-args function to: (defn derived-args [{:keys [months-to-find-tenant months-in-lease lease-cycles months-to- sell] :as args}] (assoc args :months-in-business (months-in-business months-to-find-tenant months-in-lease lease-cycles months-to-sell) :total-house-depreciation (total-house-depreciation args months- in-business) :year-sold (year-sold args months-in-business) :months-actively-renting (months-actively-renting months-to-find- tenant months-in-lease lease-cycles))) No lets at all. You'll see then that it's a small step from there to my suggested functional end game, which eliminates the passing of the args map altogether: derived-args would extract all the named arguments and pass just the specific ones to each function. No big deal, though; there are advantages to the map approach. Looking good! -R -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: newbie question: Please help me stop creating constructors
I'm just trying to figure out what the right pattern is because the fact that I'm forced to make the derived values into thunks feels really wrong but I honestly don't know what's right in the context of Clojure. I don't think you're using the term thunk correctly. A thunk is (usually) a no-argument function, typically used for things like delayed evaluation, and typically capturing some environment. E.g., (defn hello [thunk] (println Hello, (thunk))) (defn make-name-thunk [name] (fn [] name)) (let [n (make-name-thunk Jim)] (println Calling hello...) (hello n)) You are not making your derived values into thunks by this definition. Your derived values are just that: values, computed by functions. Compute them when you need them by invoking the appropriate functions with the appropriate arguments. Can you explain what you mean by thunk? -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: newbie question: Please help me stop creating constructors
I don't expect anyone to actually read, rather I was hoping some folks who know Clojure might just glance at it to get the rhythm of the math. It's the pattern, not the detail that matters. How should what is essentially a monster algebra equation be codified in Clojure? I looked at your PDF. You express the equations as functions. Turning your equation notation into function notation -- I'll use Haskell's as an example: OpportunityCost = Rent - Sell becomes opportunityCost r s = r - s or in Clojure: (defn opportunity-cost [r s] (- r s)) Note that the implicit arguments in your equational notation become explicit arguments in the functional version. How do I compute r and s? Why, with functions of course! Let's take Sell as an example. Sell = HouseSaleProfit0(1 + RealMonthlyOpportunityCost)^MonthsInBusiness which becomes (defn sell [hsp-zero rmoc mib] (* hsp-zero (exp (+ 1 rmoc) mib))); Assuming exp defined. Now, assuming that we have Rent, HSP0, RMOC, and MIB calculated (which follows the same pattern), we compute our OpportunityCost: (defn -main [] ;; TODO: extract user arguments. ;; ... (let [hsp-zero (...) ; More calculation. rmoc (...) mib (...)] (println Opportunity Cost: (opportunity-cost rent (sell hsp-zero rmoc mib To turn this into your final code, you need only: * Keep walking through your formulae until you've expressed everything as functions; * Grab the nineteen or so leaf values you need from the user, and plug them into your calls. When you have intermediate values, bind them with let, as I show above. Note that: * Each of the functions stands alone, defined in terms of its arguments, and follows naturally from your equations * You can compute any intermediate stage, and print them out, log them, whatever * There are no global values or bindings * You can name each intermediate value using let; your main function can essentially be a sequential set of intermediate calculations, just like your PDF. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: newbie question: Please help me stop creating constructors
For the method tax_deductible_expenses to run it ends up requiring 19 user defined values. That's a whole lot of arguments to pass into a function. Obviously I could wrap them up in a StructMap but then I get expressions like (+ 1 (args :B)) which doesn't seem much better than (+1 (B)). Pass them in as a map, and destructure at the start of the function: (defn tax-deductible-expenses [{:keys [management-fee tenant-finding-fee ...]}] ...) The issue I'm really trying to put my finger on is - these arguments really and truly are 'constants' within the context of the calculator. But they are constants whose values are not known as compile time but rather are known at run time. That they're constant does not mean that you shouldn't pass them as arguments to your functions. Most values obtained from users or config files are such run-time constants. Heck, many values in most programs are -- HTTP listener port, log file location, etc. You still invoke your HTTP server with a :port argument. Indeed, the more fixed values you have, the less likely it is that you should define a var for each. Maybe one var containing a map, but I'd still pass the map around rather than having each function implicitly refer to it. It makes testing easier. Does Clojure have a way to express a 'late bound' constant or is the 'right' solution to pass around 19+ arguments to functions or passing around StructMaps or making everything into thunks? The reason you pass them around as arguments is so that the behavior of your functions is precisely determined *only* by its arguments -- they are pure. That means that you can memoize them, easily write tests for them, have them work correctly when part of a lazy sequence (which will often be evaluated outside the scope of your bindings), etc. For example: how would you compare the tax-deductible-expenses of two clients? You'd need to invoke the function twice, with a huge nest of bindings around each call. Much better would be to store the appropriate values in two maps, then say ( (tax-deductible-expenses 0 john-data) (tax-deductible-expenses 0 bill-data)) -R -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: newbie question: Please help me stop creating constructors
It seems however that the consensus of the group based on what I've said so far is to pass around state in a structmap. Not necessarily a struct-map. Just a map. This is nice in that it makes each function completely self contained (e.g. no external references). It's unfortunate in that it now means that every single function needs this extra argument and every variable access either needs to use the :keys feature in the arguments or has to directly refer to the keys in the map. Not necessarily. At some point your functions should be fine-grained enough that they only take a couple of arguments. As soon as you drop below 6 or 7, where they're all mandatory, switch to ordinary function argument style. Wherever you call those functions should do the unpacking. E.g., (defn outer-1 [{:keys [foo bar baz noo]}] (let [interm (foo-bar foo bar) fiddle (frostrup baz noo)] (tweep interm fiddle))) After all, your house-sale-profit function should be expressed in terms of two arguments: (defn house-sale-profit [house-sale-price house-sale-expenses] ...) It doesn't care about the other 17. Another thing: that big entry point function is like a much tidier version of the Java constructor that you created with 19 arguments -- tidier in that you can use named keys or a map to identify the arguments. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: newbie question: Please help me stop creating constructors
So imagine the user submits a value A. I will have a value B whose definition will be something like (+ 1 A) (yes, more complex in reality, but you get the idea). In Java, everything's an object, so you go about this by defining some class. All of its private members, its constructors, and its accessors are there to support one thing: should I sell or rent my home? That is, rather than saying something like: should-i-sell given that: current-home-price = 100,000 current-interest-rate = 5.2% ... you say HomeCalculator c = new HomeCalculator(10, 5.2, ...); boolean shouldSell = c.shouldSell(); and the logic is tied up in the shouldSell method definition. When someone calls .setA(...), you have to recompute B, or you have to make sure that B is dynamically computed in .getB(). That's not how you do things in a functional programming language. You don't define global variables B and A. Define functions that compute things; thread them together; and then push your values in the top. Start from the bottom up and the top down together; build a tree of functions that compute what you want. For example, you might think ah, I need to figure out my monthly payment on my mortgage. That's a function of the initial principal, the term, and the rate: (defn monthly-payment [principal term-in-months interest-rate] ...) Then you want to figure out how much more or less you'll pay, assuming a growth in rents of a certain percentage, over some number of months spent living in the house. Let's start by computing a sequence of rents, increasing over time: (defn monthly-rent [starting-value monthly-increase] (lazy-seq starting-value (monthly-rent (* (+ 1 monthly-percentage-increase) starting- value) monthly-increase))) then we want to weigh these against each other: (defn rent-cost-over-time [starting-value monthly-increase months] (reduce + (take months (monthly-rent starting-value monthly- increase))) (defn mortgage-cost-over-time [principal term-in-months interest-rate months] (...)) You get the idea: you're building a library of *pure* functions, each of which does one thing to some inputs, and might rely on the others. Now you're ready to phrase your question as a function: (defn should-i-sell [initial-mortgage-principal monthly-interest-rate months-already-paid-into-house ...] ) If you want to use keywords to denote named arguments, you can do that: (defn should-i-sell [ args] (let [{:keys [initial-mortgage-principal ...]} (apply hash-map args)] ...) No bindings. No global definitions. No redefinition. No state. User input comes in to your function and is passed through other functions. Eventually you get a value. If the user input changes, re-run the function. Dataflow programming is overkill for what you're doing. You don't have primary values and dependent values: you have function inputs, and functions that compute values from inputs. Hope that helps... -R -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: clojure-dev: #55: clojure.contrib.sql expects *err* to be a PrintWriter Ticket updated - Resolution?
Patching swank might be appropriate but doesn't address several incorrect assumptions made by c.c.sql: 1) *err* and *out* promise to implement java.io.Writer in the documentation not java.io.PrintWriter. Calling .println on *out* or *err* is not appropriate. I started in the same mental place as you. See http://groups.google.com/group/clojure-dev/browse_thread/thread/369734ff42cbb06a/cc9e30534c78b6b3?lnk=gstq=sql+println#cc9e30534c78b6b3 Steven asserted that this was a Clojure doc bug, not a sql bug. Given that Steven added *err* to Clojure, I trust his judgment about what the code is supposed to do :) I personally still feel that switching those .printlns to printlns would be neater, but it's really no big deal. It's also cheap to wrap a Writer in a PrintWriter, as I did with swank- clojure. 2) c.c.sql shouldn't assume that we want anything printed at all?! Just throw the SQLException. Printing to *err* is acceptable IMO. This is the common should my library write log messages, and if so how? problem. I'd rather have it print to *err* than use Java Logging. 3) c.c.sql's use of throwf unnecessarily wraps the SQLException into java.lang.Exception. Doing so isn't useful, especially if you want handle an SQLException earlier than an unknown exception. That sounds like a reasonable complaint. Perhaps mail Steven to discuss, or create an Assembla issue? -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: contrib.sql with postgresql is really a problem
My first problem was to save a timestamp value. I defined a field in pgsql as timestamp and wasn't able to store a simple timestamp value because I got type mismatch errors and it also displayed the statement which I could copy and execute successfully in pgadmin which confused me a lot. I seem to recall being able to store a java.sql.Timestamp in my PG DB. E.g., I have a now function: (java.sql.Timestamp. (.getTime (java.util.Date.))) so I could successfully save timestamps to my db by casting my strings to a java timestamp (timestamp (params :foobar)). This is really nothing to do with c.c.sql: JDBC is in charge of converting Java objects into native DB datatypes. It simply doesn't know how to cast a String to a Timestamp. However, what I complain about is that in no fracking example any typecast was used and I assumed this is normal as supposed to other interfaces/libs I've used in the past. I've never used typecasts in this way. Using the correct Java class has always been my solution. Possibly you're experiencing a disconnect when you're investigating issues. In every case where some Java object is being interpolated into a query, it's JDBC that's doing the work. Thus, you should be searching for http://www.google.com/search?q=jdbc+timestamp+postgresql (981,000 results) not http://www.google.com/search?q=clojure.contrib.sql+timestamp+postgresql (1,030 irrelevant results) c.c.sql is a handy wrapper around JDBC. HTH, -R -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: clojure-dev: #55: clojure.contrib.sql expects *err* to be a PrintWriter Ticket updated - Resolution?
Why log anything at all? The relevant information is (or can be) stored in the exception. I don't want to see clojure contrib embrace the catch/log/re-throw idiom. I couldn't find any other code in contrib that follows this approach. Ain't my code. I was simply saying I prefer libraries to print to *err* than drag in a dependency on a bad logging library. I suggest you write up your thoughts and start a discussion with scgilardi... -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: clojure-dev: #55: clojure.contrib.sql expects *err* to be a PrintWriter Ticket updated - Resolution?
The above thread suggests defining *err* as a PrintWriter instead of as a Writer. Has this been patched, and is it official? If so, I'll patch clojure-swank to use PrintWriter. If not, I'll patch clojure.contrib.sql to not use println. I patched swank-clojure: diff --git a/src/swank/core/server.clj b/src/swank/core/server.clj index 31c25ee..972e74a 100644 --- a/src/swank/core/server.clj +++ b/src/swank/core/server.clj @@ -57,7 +57,7 @@ (defn- socket-serve [connection-serve socket opts] (with-connection (accept-authenticated-connection socket opts) -(let [out-redir (make-output-redirection *current-connection*)] +(let [out-redir (java.io.PrintWriter. (make-output-redirection *current-connection*))] (binding [*out* out-redir *err* out-redir] (dosync (ref-set (*current-connection* :writer-redir) *out*)) It would be nice to see this upstream. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Clojure and OOP
I suspect that Clojure is actually more suited to OOP than Java, assuming you're going by Dr. Kay's definition. :) Another Kay quote: I invented Object-Oriented Programming, and C++ is not what I had in mind. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Simple clojure and contrib install, with SLIME ... ?
What are other people doing to maintain their installations? Is there some simple way to keep all of these projects up to date? Or do people simply not update all of these projects often? I suck it up. Fortunately I was in the process of switching to Leiningen when contrib suddenly moved to Maven, but I can't say I like it -- IMO there was nothing wrong with ant for contrib, which has no dependencies! Swank-clojure I have checked out from GitHub, and I rebuild as appropriate when switching between 1.1 and 1.2 (which seem to produce incompatible compiled code). -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Help me make this more idiomatic clojure
You can use get on Properties. Use .foo for method calls. Use literal vec syntax, not list. Use or for conditional branches instead of (if foo foo ...). Untested: (defn obtain-local-connection [vmid] (let [vm (VirtualMachine/attach vmid) props (.getSystemProperties vm) acquire-connector (fn [] (get (.getAgentProperties vm) com.sun.management.jmxremote.localConnectorAddress))] (or (acquire-connector) (do (.loadAgent vm (apply str (interpose java.io.File/separator [(get props java.home) lib management-agent.jar]))) (acquire-connector -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: scope of binding
You can also capture the binding. This looks a little ugly, but it works: it grabs the binding eagerly, and returns a closure that dynamically binds it when the function is invoked. (binding [*v* 2] (map (let [v *v*] (fn [n] (binding [*v* v] (f n [1 1 1])) Obviously you wouldn't use it in this instance -- use doall, or better yet rewrite your function to not use dynamic bindings -- but for larger jobs it works fine. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: newbie question: splitting up source files
It might be helpful if the documentation at http://clojure.org/namespaces mentioned how to split out a namespace into multiple files. I never split a namespace into multiple files: I split my project into multiple namespaces. That way I can simply :require and :use them from each other, and let the dependency system take care of loading. In your case, I'd have: ;; foo/main.clj (ns foo.main (:use foo.a foo.util)) (defn main [] (print hello from main\n) (aaa FOO-MAIN) (util FOO-MAIN)) (main) ;; foo/a.clj (ns foo.a (:use foo.util)) (defn aaa [arg] (print (format hello from aaa: %s\n arg)) (util FOO-A)) ;; foo/util.clj (ns foo.util) (defn util [arg] (print (format hello from util: %s\n arg))) To make all this directly executable, add (:gen-class) to the main ns, and specify foo.main as the Main-Class in your jar. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: compiled namespaces referencing each other
which invokes (compile 'foo.main). I then get java.lang.Exception: Unable to resolve symbol: a in this context. foo.main uses foo.util. foo.util uses foo.main. That's a circular reference. There are ways around this (e.g., create foo.main in foo.util, then use declare to ensure that `a` exists), but I suggest you rearrange your namespaces to avoid the circularity. Another thing I've noticed is that even during compilation, the order that functions are definied in a source file matter. That makes sense to me when a clj file is run as a script, but when clojure code is getting compiled, why should it matter which order things are defined in? Is this behavior related somehow to my compilation error? Because you can redefine things. Order does matter. If you want a forward declaration, use declare. http://richhickey.github.com/clojure/clojure.core- api.html#clojure.core/declare -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Clojure for system administration
in a bash (or other language) script anyway to handle the classpath, The classpath is a perpetual source of frustration. It drives me nuts every time I have to restart swank to work on a different project with a different classpath. It certainly means that something like a Clojure shell would be unnaturally limited. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Is this possible in Clojure?
* You don't have to fiddle with magic names. The user can choose himself. These aren't magic names, they're just like you keywords, except they're symbols, and they're not magic because they're defined by the columns of the table. Or, I may be misunderstanding your use of the term 'magic'. They're magic because they're not introduced via normal lexical scoping. Not magic: (let [x 5] (do-something (foo x))) Magic: (with-implicit-wizard (do-something (foo gandalf))) That seems to work great, what I'm fuzzy on is the whole macroexpansion thing and when it occurs. As in this example everything is known at compile-time, is this macro-expanded at compile time? Can this sort of macro work just fine when the column information is only known at runtime? Are there any performance considerations? The macroexpansion occurs at compile time. If you have all the knowledge at compile time, you can do the work then. If you don't, the macro has to expand into code that does the work at runtime. For example, to write a macro that prints upper-cased strings, you might do this: (defmacro all-upcase [ args] `(println ~@(map (fn [x] (if (string? x) (.toUpperCase x) `(.toUpperCase ~x))) args))) ... it does the upcasing at compile-time for static strings, and at runtime for everything else. You can see what happens by using macroexpand: user= (macroexpand '(all-upcase foo bar x y)) (clojure.core/println FOO BAR (.toUpperCase x) (.toUpperCase y)) user= (let [x hi y there] (all-upcase foo bar x y)) FOO BAR HI THERE -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Is this possible in Clojure?
OK, I hope you can see the difference though between that and what I showed. Of course I can; I'm just illustrating a point by exaggeration. They are not the same; in your example: - It's not clear what the magic symbols are - The user does not specify the magic symbols (as they did in mine) It's not clear in the case of multiple packages or namespaces. (In which package does name get interned? It depends on *when* the string is interned, because that decides the enclosing scope. Or does newLISP not have packages?) Neither are the names specified in a query such as SELECT * FROM people. Who knows what'll happen when you do SELECT p1.name You're about half-way to complete anaphora when you're starting to pull symbol names out of syntax-laden strings (or databases). That's magic, at least when compared to ordinary lexical symbol reference. Given that there's little to no advantage to doing this, I don't see the point. This sort of programming style is easy to abuse and can sometimes lead to confusion if handled incorrectly, but when applied in the appropriate manner it can be extremely useful. The 'for-query-with-db' function is a good example of doing this correctly because it: - Documents its behavior - Creates symbols based on user input, not of its own accord as in your example - Clearly distinguishes them through a special naming convention - Has advantages over other forms of solving the same problem ... and it's a bad example, because it: - Quietly and maybe accidentally shadows variables from enclosing scopes - Fails to nest queries which share names - Silently interns new variable names in your packages - Uses eval (which apparently is fine in newLISP, but as a Common Lisper and Clojurite strikes me as pointless) - etc. I see no point in doing this rather than going the conventional macro route. c.c.sql, for example, would do this: (with-query-results res [SELECT name FROM people] (println (:name res))) -- res is a map. You can pass it around, access its values, and your own function `name` doesn't get shadowed by your query. c.c.sql also allows you to synthesize queries from Lisp forms, which I think is more useful than trying to extract symbol names from a SQL string. The macroexpansion occurs at compile time. If you have all the knowledge at compile time, you can do the work then. If you don't, the macro has to expand into code that does the work at runtime. Thanks for the example and explanation! Sure thing! -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Is this possible in Clojure?
NAME (not name) may be interned in the sense that it will exist somewhere in the symbol tree, but that doesn't matter—at all. At least in newLISP. In Clojure it may have some consequences and if so, that would be a valid argument to make, I'd be interested to know what they are if that is the case. It matters in Clojure because symbols are interned in namespaces, or they have no namespace. Symbols from different namespaces denote different things: for example, this works just fine in Clojure, even though it's a Lisp-1, because the local `keys` has no namespace. (let [keys Chubb] (println (clojure.core/keys {:foo :bar}))) Neither are the names specified in a query such as SELECT * FROM people. Who knows what'll happen when you do SELECT p1.name This is incorrect. A query like SELECT * will not have any issues getting the correct, expected names from the table definition. You can check the code again, there's no string parsing going on with the query. My point with that example is that it really is magic: the symbol name comes out of the DB, and isn't even mentioned in the syntax of the query. Against a different DB you'll get different results -- your code might even throw an error about a symbol not existing. What does newLISP do for a query like SELECT p1.name, p2.name from people p1 JOIN people p2; ? It's also exceedingly unlikely it will happen due to naming convention and even if it happens, it's *still OK* because nothing breaks because things are only shadowed within the scope of the macro call and you're explicitly expecting to use the NAME symbol, etc. There's zero confusion and zero ambiguity. The literature about hygienic macros disagrees with 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 Note that posts from new members are moderated - please be patient with your first post. 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: Is this possible in Clojure?
Enlive has to reconstruct HTML from its data structures. This, on the other hand, mostly just prints already rendered strings, and calls any clojure functions/macros along the way. Most CL/Clojure HTML output systems, like clj-html or CL-WHO, produce optimal output by processing the macro input. See http://weitz.de/cl-who/ for a description. This is one of the reasons to use macros: you can do a huge amount of work once, at compile-time, leaving the runtime with less to do. Templating does not require eval. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Is this possible in Clojure?
And he does have some eval's in there: http://github.com/brool/gulliver/blob/master/template-servlet.clj But my Clojure knowledge isn't yet good enough to tell me whether he's using eval only once or on every render? It uses eval at runtime, but only once: that code slurps a template, turns it into s-expressions, then uses eval to define a function named `render` in the appropriate namespace. Pretty nice. That function is just like one defined in Clojure source: it'll get JITed, for example. One might avoid the (minor) runtime work by precompiling templates: translating them into the equivalent Clojure source on disk, which can then be treated like ordinary source files. That's what Cheetah does for Python. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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 advice on java interop namespace hunting
I've found myself a few times in a situation where I'm banging some java code into clojure, and the java source uses import foo.* blah.* bar.* Now Clojure requires explicit class naming (which I fully support) so I end up spending a good slice of time googling java SomeWierdClass someapi to get all the import names, recompile, find next one, google, update... its a very slow cycle. How do other people do this? That's pretty much how I do it, though I don't really use the compiler to prompt me -- I try to get it right the first time. I spend a lot of time looking at Javadocs, replicating work that Eclipse would do for me. jar tf somelib.jar will produce a nice list of classes... -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Transients question/feedback
My question is: why not have each conj! produce a new, lightweight TransientVector instance pointing to the same shared data? ... My guess is that the resulting ephemeral garbage would have only a small effect on performance, retaining most of the advantage of transients, but improving their safety. Would any of the Clojure experts care to comment on whether this seems like a worthwhile exercise? (Not that I'd call myself a Clojure expert, but...) Transients are used all over the place, including in Clojure's own non- transient functions (such as merge). If you're adding a new TransientVector instance on every call to conj!, you might as well just use conj. Making transients slower -- even by a small amount -- strikes me as contrary to Rich's position. After all, transients are meant to be an optimization technique: write your code with persistent data structures, and if you find yourself banging on a chain of maps, say, add some !s, transients, and persistent!s, and you'll see a performance gain. They should never leave the scope of a particular function (or small group of functions), and by the time you're done writing you should make sure that you got it right. Making them safer is analogous to asking for checks to be added to unchecked math operations. You should *never* be shoving transients into vars, IMO. That said, I agree with Stuart that a debug level of Clojure might be useful, making the get it right part easier. I don't favor a separate build, unless it's unavoidable: I think that Common Lisp's declarations are a reasonable starting point for discussion. Imagine if macros could see an environment with speed/space/safety attributes, and could generate appropriate code... -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Lazy (apply concat ...) ?
I'm wondering whether (apply concat ...) can be re-written to be lazy. ... -Behavior in 1.1.0-- The operation is eager. It's not: it simply uses chunked sequences, so the first 32 elements are evaluated together. user= (def temp (for [i (range 50)] (do (println i) [i i i]))) #'user/temp user= user= (def temp2 (apply concat temp)) 0 1 2 ... 30 31 -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Lazy (apply concat ...) ?
Oh I see. Thanks for the explanation. I always assumed that chunked sequences can be viewed as purely an optimization and transparent from the user. Is there a way (short of writing a lazy version of apply concat) that I can achieve my desired result? I've heard talk about trying to provide some option for zero-lookahead lazy sequences. I don't think any API has been stabilized, though. One workaround I've used is to use delay to avoid the execution of individual elements, but that doesn't really work in this case: you need to force them in order to apply concat. Maybe something like: (defn force-concat [ xs] (when xs (lazy-seq (concat (force (first xs)) (force-concat (rest xs)) (def temp (for [i (range 50)] (delay (do (println i) [i i i] (def temp2 (apply force-concat temp)) (println (take 10 temp2)) It behaves oddly on my machine, but I think the principle is sound... -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Lazy (apply concat ...) ?
Am I understanding this correctly? It seems laziness is only an option in batches of 32 now. Indeed. *Processing* *chunked* lazy sequences can only be done in batches of 32. Custom lazy sequences (using (lazy-seq ...)) don't suffer from this. You might be interested in this blog post: http://blog.fogus.me/2010/01/22/de-chunkifying-sequences-in-clojure/ and http://clojure-log.n01se.net/date/2010-01-22.html#15:01 -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: update-in and get-in why no default?
There are still some sharp edges I'm not sure about: (A) user= (get-in {:a 1} []) {:a 1} ;; this is existing behavior, but I feel the result should be nil +1 for nil I think I disagree. If you view 'get-in' as an unwrapping operation, unwrapping by zero steps should return the existing collection, no? {:foo {:bar {:baz 1}}} [] = {:foo ... [:foo] = {:bar ... [:foo :bar]= {:baz ... This maps trivially to a sophisticated user's recursive mental model of get-in: (defn get-in [m ks] (loop [looking-at m first-key (first ks) remaining-keys (rest ks)] (if-not first-key looking-at (recur (get looking-at first-key) (first remaining-keys) (rest remaining-keys) ... if there are no keys, it returns m. That's intuitive to me, at least. Can you explain why you think the result should be nil? (B) user= (get-in {:a 1} nil) {:a 1} ;; this is existing behavior, but I feel the result should be nil (nil is a seq so not an exception) +1 for nil As above: I equate nil with the empty sequence. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: apply macro to 'argument' list?
if and were a function then i could do (apply and [true false]) and get false, i think. is there some shorthand for doing that given that apply doesn't work with macros? (every? identity [true false]) -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: apply macro to 'argument' list?
is there a general shorthand rule for (apply macro [arg1 arg2])? given your version i'm assuming no :-) (apply #(macro %1 %2) [arg1 arg2]) Doesn't extend to arbitrary number of arguments, though. every? does. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: apply macro to 'argument' list?
Doesn't extend to arbitrary number of arguments, though. that was sorta a deal-breaker. :) A broader analysis of this: because macros work at compile-time, not at runtime, you need to know the number of arguments in advance. That means that any solution which requires a variable number of arguments to be passed to a macro -- such as getting its effects at runtime using apply -- can't work, and must be avoided or solved using eval (as DanL mentioned). (Or one of the arguments needs to be a sequence, and the macro expands into code that walks it at runtime. That's still a fixed number of arguments.) In Lisps, there are usually two solutions to this: * Have a complementary version: statically one uses 'and', dynamically one uses 'every?'. Often the dynamic version is implemented in terms of the static version. * Provide only the dynamic version, and use a compiler macro to get some static benefits. This solution isn't available (at least to user code) in Clojure. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Clojure Conference Poll
Conference alignment is smart, but to which conference? I suppose it depends on whether the conference organizers prefer to convenience the audience of JavaOne or ICFP. I'm unfamiliar with what sort of folks go to JavaOne, I'd imagine many of them aren't familiar with Clojure and wouldn't be interested in paying (or convincing their employers to pay) to attend the conference. I attended JavaOne last year, primarily for SailFin and Clojure. It's *huge*. There was interest for Clojure, but there are also aisles upon aisles of awful middleware/reporting software brokers. If I wasn't sponsored to go, I wouldn't have paid for it. I imagine the overlap for ICFP and ILC (which isn't happening again until 2011) would be a higher percentage, if not a higher absolute figure due to the huge size of JavaOne. Whether most of the JavaOne co-attendees would actually be 'genuine' Clojurites in the making, or just Java drones looking for fresh buzzwords, I can't say. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: apply macro to 'argument' list?
A broader analysis of this: because macros work at compile-time, not at runtime, you need to know the number of arguments in advance. That means for the case of 'and', it seems like if one had other call-by-* semantics available in the lisp, then one wouldn't have to use a compile-time macro? Depends on why you're using a macro. Calling semantics don't matter in the case of a macro. The definition of macro is that it generates code prior to runtime. If you don't know the arguments to be provided (e.g., you're using apply), macroexpansion simply cannot occur. (You can delay macroexpansion until runtime, but we've got a word for that: eval.) You can sometimes avoid the use of a macro by using alternative evaluation strategies, whether that's provided by odd calling semantics, by pervasive laziness (e.g., one can implement `if` in Haskell using a function), or by manual thunking (or the use of `delay`). If that's what you mean, then the answer is yes. For example: If `and` were a variadic function (defined for illustration's sake, not efficiency): (defn and* [ args] (if (empty? args) true (and (first args) (and* (rest args) then it will evaluate all of its arguments, not short-circuit: user= (and* (do (println One) false) (do (println Two) true)) One Two false Now, if we explicitly thunk our arguments, and define `and**` to un- thunk: (defn and** [ args] (if (empty? args) true (and ((first args)); Changed. (and** (rest args) we get similar short-circuiting behavior to the macro version: user= (and** #(do (println One) false) #(do (println Two) true)) One false Does that answer your question? -R -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: apply macro to 'argument' list?
yup. and i mean i wish lisp had that ability, rather than forcing everything that isn't strict-evaluation functional argument passing into compile time macros. of course, it only moves the newbie (like me with macros) hey, these things aren't all exactly the same?! reaction somewhere else -- away from macros, and on to why does if(a,b) have different side-effect results than foo(a,b)?! Pervasive laziness can be a curse itself; lots of Haskell programmers expend effort to avoid it for performance reasons. Generally, things are the way they are for a reason. (Not always true, but it's worth finding out.) Be careful what you wish for! With the ease of manual thunking and delay, and Clojure's lazy sequences -- the main place you want laziness -- I don't long for the abandonment of eager evaluation. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: newbie python/clojure and java.lang.OutOfMemoryError: Java heap space
What's puzzle me is that past at certain number (10 millions), clojure chocks and throw a «java.lang.OutOfMemoryError: Java heap space», continue for a while and stop before completing the sequence. The JVM puts a limit on the amount of memory that will be allocated. Try adding -Xmx512m to your java invocation, and you'll get much further. Also make sure you're running with -server. It is also 10x slower compared to python, that manage to complete it successfully. You might have to run a method tens of thousands of times before the Hotspot JIT will optimize an invocation. Furthermore, (filter even? (range 1000)) in the REPL will try to print the sequence. That's no good. To attempt to time this fairly, I tried user= (time (count (filter even? (range 1000 Elapsed time: 1690.235 msecs 500 user= (time (count (filter even? (range 1000 Elapsed time: 1127.633 msecs 500 It stabilizes quite quickly. Python: import time def tryout(): ... t1 = time.time() ... print len(filter(evenp,range(1000))) ... t2 = time.time() ... print t2 - t1 ... tryout() 500 3.80207896233 tryout() 500 4.21358513832 In short: Clojure is about 4x faster than Python on this trivial example. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: newbie question about ns and :require
now if i only knew when to use ' or : or nothing, and which in (ns) vs. inline in the repl. Simple: ns is a macro, so you don't need to quote. use and require are functions, so you need to quote their symbol arguments. ns uses keywords to identify its directives (:use), and functions (use) don't, because they're identified by regular symbols. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Debugging in Clojure
That said (and I'm not trying to make this a charged statement ... just a way to learn more) I had always thought that one of the key things that made lisp so complete was that programs don't just crash ... that debugging is fully-baked into the *core* of everything. Now, I don't remember much about the debugging capabilities of, say, CL, but my understanding is that *after* a crash, you can interrogate the state of objects. . . .rather than having to preemptively guess at what you may want to know in the future. This is largely down to CL's condition system: problems are usually reported as conditions, which stop execution without unwinding the stack. Unlike exceptions, you typically get a REPL in the environment of the condition (so you can view locals, inspect objects, etc.) — a bit like being dropped into the debugger in an IDE. Unlike an IDE, you can *do things* to the running program, and the condition often offers restarts (e.g., a compile failed condition might offer to retry the compilation). That means you can fix and continue, or just find out what went wrong. These make an unexpected condition into an interactive process, rather than merely an opportunity for logging. By the time you were ready to ship your app, you'd experienced most of the failures, and introduced static or dynamic handling for those problems. Unfortunately, Java can't match CL's condition system. There are steps towards including some of its power in Clojure (see errorkit). That said, I still use tracing extensively in Common Lisp development: things might not crash, but I still need to see what's going on to identify the root cause of some high-level behavior. I also use print statements: often trace output is too verbose, or I need to see the result of some computation on an intermediate value. Sometimes there's no condition to raise. Trace is better than logging. Logging just seems like a flawed approach (as others have pointed out). I mean, Log4j (or related) is desired in Java so that someone can get more information without a recompile. But in a dynamically run language or in an environment where you aren't just the user of some closed-off code, you may as well just put print statements where you need them. The latter is what I was advised to do in Clojure, and it was a real turn-off for me. Maybe the lack of appeal comes from having to squeeze in that extra do nesting -- or maybe because you then have to go through and remove all that stuff later. Or in the case of logging? you always leave it there, FOREVER. Even if you never end up caring about some state in a production environment!!! I disagree that logging is a flawed approach. Tracing is an interactive tool. Logging allows you to see what happened before you were watching (which is important in the case of systems that are running for months or years, on many different machines, handling millions of requests). It also helps to produce a usable record of events in your program, which aren't always visible in trace output — e.g., this request was invalid because this header appears to be truncated. Try spotting that in trace output. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Clojure Conference Poll
as far as pricing goes, how does something in the $199 range sound? we can probably add a tutorial day Friday for a small additional cost, say $149...? we can certainly have some well-known clojurians conduct the tutorials, I'm sure we'll have plenty of real world clojure experience in the house... Sounds very reasonable (though from talking to organizers of other conferences I'd be careful about committing to prices like that until you figure out how much the space and catering are going to cost…). Early-bird registration for ILC 2009 was $210, with standard registration $250. The event had sponsors. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: A new lisper's question about a macro
The former is a lot clearer to read, as it uses standard Clojure datastructures. ... which offers other advantages beyond the human, such as (def page-names keys) user= (page-names foobar) (:page :posts :post) Power comes from algorithms × data structures, and hiding the data structures — whilst sometimes beneficial — reduces one's ability to leverage existing algorithms. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Promise/Deliver use cases
delay/force definitely do not do what I'm describing. What we want to is something like a continuation as mentioned by Chouser. We want to block the thread of execution until some point in the future when the values become available. I'm not sure that what you described describes what you want :) Yes, if you want to block the current thread to wait for a value computed by a background thread, you need promises and futures. However, you were explicitly talking about a use outside the context of concurrency. If you don't want concurrency, only delayed execution, then use delay instead. In your example you have to *know* that all the tests have run in order to accumulate results. No you don't — force is synchronous. By the time that `doall` has finished, all the tests have run and their results have been accumulated inside the delays. As I said, if you want to run tests in parallel, then you're not talking outside the context of concurrency. Futures are awesome, but you can't argue that they're not a parallel construct. By using promise/deliver you can remove yourself from caring about that at all. With a recursive data structure this becomes annoying very quickly, you have to bookkeep where you are if you use delay/force. No you don't — simply always call `force`, just as you always call `deref`, and the delayed computation will be done if necessary. (In fact, you can use @, just as you can with refs and promises.) Here's an example of a trivial recursive arithmetic evaluator that prints the whole tree, returning a delay which captures the execution. When forced, it prints the arithmetic results back up the tree. Execution occurs once. (defn form-delay [v] (if (number? v) (do (println Saw number v) (delay v)) (let [[op args] v] (println Seen form with operator op , args args) (let [delays (map form-delay args)] (delay (let [res (eval `(~op ~@(map force delays)))] (println Result is res) res)) user= (let [de (form-delay `(+ 5 (- 3 2)))] (println First run: @de) (println No bookkeeping: @de) (println Delay: de) @de) Seen form with operator clojure.core/+ , args (5 (clojure.core/- 3 2)) Saw number 5 Seen form with operator clojure.core/- , args (3 2) Saw number 3 Saw number 2 Result is 1 Result is 6 First run: 6 No bookkeeping: 6 Delay: #de...@58e22f2b: 6 6 You'll see that: * It runs on one thread * There is no bookkeeping of what's been forced and what has not; you can force multiple times without re-execution * It can do arbitrary work during the tree walk (printing Seen form...), and during evaluation (printing Result is), and the two phases are separate. By creating the future computations to be performed during the traversal you later only need to deliver each individual test result. As tests come in they automatically trigger the next level of computation (the aggregate result). You don't need track relationships between tests at all because that was determined by the first traversal. There are only two places where futures might apply in what you're talking about: * To run tests in parallel, which you explicitly disregarded * To have the tests depend on each other's values (which doesn't seem very smart to me). Use futures and promises for parallelism or dataflow-style work. Use delay for non-parallel, synchronous delayed execution. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Promise/Deliver use cases
You're right. Here's a recursive example of what I was trying to do with promise/deliver: http://gist.github.com/284957 And with delay/force: http://gist.github.com/284972 Nice comparison, thanks for sharing. I suppose the one thing I like about promise/deliver is that promises can be watched making it perhaps more extensible? Anyone can get just attempt to deref the value inside a future to watch it. With delay/force it's harder to add new functionality without mucking directly with the code. Or is there a better way to handle this that I haven't thought of? Nope, you're right about the advantages — futures (being essentially control abstractions for tasks running on threads) are richer objects. Delays have downsides: for example, just printing a delay will cause its value to be computed. And of course using promises and futures introduces parallelism into your code, which is sometimes desirable. I see a kind of analogy — futures : delays :: refs : vars or atoms. Both futures and refs hide a lot of functionality under the hood (threads and synchronization for futures, the STM for refs), whilst delays and the other state approaches are more applicable for local or non-concurrent situations. Delaying computation with delay feels like local accumulation using an atom, whilst computation with promises and futures feels like distributing state operations with refs. Thanks for the insights Richard. Thanks for the discussion! -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Dependency management
Richard, this doesn't address your larger points, but I wanted to make sure you're aware of http://build.clojure.org which is a maven repo for clojure contrib artifacts. At /snapshots, there are builds for Clojure 1.2 (1.2.0-master-SNAPSHOT). Leiningen is aware of this repo by default, so you can specify the 1.2.0-master snapshot as a dependency in your project.clj. Yup, apparently my own 1.2.0-master-SNAPSHOT was replaced by an upstream version sometime yesterday (that is, Lein found a POM). Contrib still wasn't listed, though. Thanks for pointing this out. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Dependency management
Alternatively, is it possible to at least depend on a source version of the dependency, having it compiled on the fly locally when compiling the main project ? (so that one could benefit from AOP, and this could also solve the problem of a library mixing java and clojure source) ? I've thought about this, and I think it's a great idea. I will probably implement it eventually, but it might take a while since I don't have any projects that would benefit from it right now. So it's a great opportunity for a potential contributor to step up. =) I'd do it if I knew how! What I'd like is for Leiningen to know about my ~/repos directory, which contains all of my libraries and a load of other people's. If a project file mentions a library, *look there first*. (And don't look upstream for a POM.) -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Clojure Conference Poll
What coast are you thinking? That will probably affect a lot of answers. Agreed. I'm flexible enough to go during the week (which frees up my weekend!), but I imagine that's not the case for most. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Dependency management
Now for the original question: http://groups.google.com/group/clojure/browse_thread/thread/6cef4fcf523f936 The problem is AOT compiled code. Not only. If my library refer to a function that's first defined in library-X version 1.5, and some other code uses library-X 1.4 *and* my library, then there is a fundamental problem whenever you add a dependency on both my library and the other library. This will happen any time a library's API changes and you have dependencies that cross the line. AOT compilation might make the problem appear at compile-time in some cases, or more often if the library is a compiler (i.e., leaves shreds of its implementation in your compiled code), but you don't eliminate the problem by avoiding AOT compilation. Using a sophisticated dependency system -- having a library specify its requirements, not a dumb version number -- drastically reduces these problems by resolving the requirements to a particular release, or spotting the error and failing fast. Using a dumb version system screws you whenever this occurs, *and* makes it awkward for you to manually resolve the collision. (OSGI attempts to address this by allowing multiple library versions, but Clojure needs its own classloader, and also enables code to 'flow' across library boundaries through macroexpansion.) As for the snapshots: you can find them on http://build.clojure.org/snapshots . So you (can but) don't have to put them into a local repository. Of course, you still do if you have made changes to Clojure in your local checkout. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Dependency management
BTW: commit ids as version numbers break down here, because they are not ordered. They have a partial ordering wrt a particular repo. Many repos have straight-line histories, and thus have a total ordering. Neither maven nor ivy are so simple-minded to allow only one version. How well ranges work out... I can't really know. I only know the theory for now. That the underlying system allows it is no comfort when there seems to be no obvious provision in project.clj for this: :dependencies [[org.clojure/clojure 1.1.0] [org.clojure/clojure-contrib 1.0-SNAPSHOT] [clout 0.1]] Does that mean use whatever's appropriate, or I must use 1.1.0 only? Do these version strings admit that Maven syntax? How does one tell Maven/lein never use two different versions of Clojure? How does one tell Maven to *rebuild* a library -- e.g., Compojure -- using 1.2, so that I can safely use it in my requires-1.2 project? (Or look in a repo to find a version of Compojure built using 1.2?) These are questions that I think must be addressed, because these problems come up all the time. Just this week I noticed that Apache HttpComponents 4.0.1 and 4.1 use completely different methods to apply pre-emptive HTTP Basic Auth, and have even changed class hierarchies. A version of clj-apache-http targeted at 4.0.1 won't even run against a 4.1 jar (and vice versa), *even without AOT*, because the package names are different. On the other hand, some libraries -- such as log4j -- preserve API compatibility across versions. Sorry to be raining on everyone's parade with this... -R -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Clojure for largish web application?
I've developed some smaller web applications using Common Lisp, but I'm not confident that any of the CL web servers (CL-HTTP, Hunchentoot, AllegroServe, Araneida, mod_lisp, et al) are up to handling high traffic high data sites. (Maybe they are, I just don't know). Does anyone know how good any of the CL web servers are at handling high traffic? I figure the Clojure questions in your message will get plenty of responses, so I'll address this part. A million hits a day is 11 hits per second (average). I've built SOAP servers in CL using AllegroServe that easily do 100+ requests per second on a single machine (and that's on one processor and using locks) without any tuning. Plain ol' HTTP is much simpler than SOAP (no XML parsing!); my profiling suggests that several hundred requests per second would be straightforward, particularly if your handlers didn't rely on shared state (which in CL requires locking). Of course, if you're using fancy routing systems etc., that number will fall, but CL + aserve is no slouch. Try it and see: write a trivial aserve app, set the number of worker threads high, and bang on it. Stick pound or nginx on there, run one server per core on an 8-way box, and you'll be I/O limited for sure. Farm your static content out: that allows you to handle only the dynamic load. That said, it's foolish to plan on using scaling *up* to handle larger traffic volumes, unless you want your user base to grow slower than Moore's law! Design for horizontal scalability, and you're free to use systems as slow as you like -- even Rails on MRI -- by throwing more boxes at the problem. Put your HTTP proxy on another box, and balance across N servers, each running as many processors as you need. Re load balancers: I've had good success with hardware LBs (Alteons, NetScalers), assuming you don't need in-memory sessions for some reason. They can be configured for sticky connections, too. In the software world, look at http://apsis.ch/pound, NginX, and HAproxy. The big trick is to confine your state so that you can trivially bring up a new box -- that gives you easy failover, load-balancing, and horizontal scalability. -R -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Dependency management
Just this week I noticed that Apache HttpComponents 4.0.1 and 4.1 use completely different methods to apply pre-emptive HTTP Basic Auth, and have even changed class hierarchies. A version of clj- apache-http targeted at 4.0.1 won't even run against a 4.1 jar (and vice versa), *even without AOT*, because the package names are different. On the other hand, some libraries -- such as log4j -- preserve API compatibility across versions. In fact, I just hit a concrete example of this. clj-apache-http uses httpcomponents 4.0.1. ring uses 4.0-alpha6, which is obsolete. One of my projects currently will not build because ring's transitive dependency gets pulled into lib, and apparently gets on the classpath first, causing the load of clj-apache-http to fail: [null] java.lang.IllegalArgumentException: No matching ctor found for class org.apache.http.protocol.BasicHttpContext (http.clj:274) Now I have to fix Ring, and hope that mmcgrana will accept the fix and deploy to the central repo. That fix might break someone else's code in turn. Oh, the tangled webs we weave. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Dependency management
And as for Apache HttpComponents, it sounds like they don't grok the notion that breaking backwards compatibility should only occur with a major-version change. Yeah, it's a pain to use their stuff -- I've never seen *so many packages* in one library -- but it seems to be the only feature-rich HTTP client in the Java world (y'know, that can actually set parameters on requests, that sort of thing). The JRE stuff sucks badly. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: Dependency management
They have a partial ordering wrt a particular repo. Many repos have straight-line histories, and thus have a total ordering. So how do I find out the ordering of your x repository here in my machine, possibly without having x installed. Or your repo cloned? I'm assuming that a source-based versioning system has a checkout of the source, just as a binary-based versioning system has a copy of the binary. The root cause of this situation is not a broken version system, but broken API design. If you need 4.1 and clj-apache-http needs 4.0.1 and both can't coexist, then you are hosed. That's not the problem situation I'm talking about; of course truly mutual incompatibility can't easily be resolved. I'm talking about *describing* dependencies. If my library *requires* 4.0.1, and another library puts 4.1 in its descriptor (perhaps that's the latest version on the website), then problems will arise when I combine the two. Without AOT, one will fail to build. With AOT, one will fail at runtime. The solution depends on knowledge of the library's requirements: you have to know which libraries will or won't work with a certain version (and cascade that through all of their dependencies). It might be perfectly acceptable to use the other library with 4.0.1. It might even be acceptable to use both versions simultaneously, or both if you load them in the right order! If Lein/etc. allows you to specify I must have something API- compatible with 4.0.1, and have that resolved, then great. So far I haven't seen a way to do that. Leiningen brushes it off with use semantic versioning, which isn't much help if your requirements are more fine-grained (say if the next version is -- strictly speaking -- API compatible, but you need or want to use a different implementation to reflect new API availability). I foresee a future with a lot more time spent modifying other people's project files. Maybe we need to spend a little time thinking of the appropriate way to codify workarounds for this kind of thing: imposing corrected dependencies on upstream libraries; specifying that some library should be built from source; using predicates to decide on dependencies; etc. From what you've written it appears that work has been done on dependency management systems that make some of these tasks easier (e.g., Gradle). Unfortunately, this whole adventure with Leiningen was prompted by a ton of libraries that I use moving to Leiningen, and removing any way for me to build them without it, so I'm interested in solutions for Leiningen. If I wanted to spend the time integrating these libraries with another build system, I'd restore the build.xml from their history... Thanks for the discussion. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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: What's the best way to do this?
I think it's easier to think about combining predicates separately from your file-filtering code. I'd use a higher-order function like the following (defn combine-preds [ preds] (fn [ args] (every? #(apply % args) preds))) I've noticed that most uses of this kind of thing are for fixed sets of predicates, and almost always for two, so I'd define: (defmacro both [p1 p2] `(fn [ args#] (and (apply ~p1 args#) (apply ~p2 args# Which reads nicely: (filter (both number? even?) (range 1 7)) and is probably more efficient (not that I've tested it). You can generalize this to `all`, of course. -- 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 Note that posts from new members are moderated - please be patient with your first post. 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
Dependency management
Hi folks, Apparently everyone is jumping on the Leiningen bandwagon and deleting their build.xml files. I guess that means I'm moving, too. Now, I like to keep track of Clojure master. Right now, Clojure reports Clojure 1.2.0-master-SNAPSHOT. (I don't see that in Maven Central or in Clojars, so I guess I have to put it in my local repository...?) Unfortunately, not everybody keeps up-to-date like I do; most of the projects I use demand 1.1.0-alpha-SNAPSHOT. I'm sure there are still projects that demand 1.0. Adjusting the lein script to use my local Clojure install gave me a great error: Caused by: java.lang.NoSuchMethodError: clojure.lang.RestFn.init(I)V at clojure.contrib.with_ns$with_ns__7929.init(with_ns.clj:20) at clojure.contrib.with_ns__init.load(Unknown Source) at clojure.contrib.with_ns__init.clinit(Unknown Source) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:247) at clojure.lang.RT.loadClassForName(RT.java:1523) at clojure.lang.RT.load(RT.java:396) at clojure.lang.RT.load(RT.java:378) at clojure.core$load__4869$fn__4876.invoke(core.clj:4294) at clojure.core$load__4869.doInvoke(core.clj:4293) at clojure.lang.RestFn.invoke(RestFn.java:409) at clojure.core$load_one__4810.invoke(core.clj:4130) at clojure.core$load_lib__4825.doInvoke(core.clj:4167) at clojure.lang.RestFn.applyTo(RestFn.java:143) at clojure.core$apply__3434.invoke(core.clj:478) at clojure.core$load_libs__4841.doInvoke(core.clj:4193) at clojure.lang.RestFn.applyTo(RestFn.java:138) at clojure.core$apply__3434.invoke(core.clj:480) at clojure.core$use__4865.doInvoke(core.clj:4271) at clojure.lang.RestFn.invoke(RestFn.java:409) at leiningen.core$eval__5$loading__4758__auto6.invoke(core.clj:1) at leiningen.core$eval__5.invoke(core.clj:1) at clojure.lang.Compiler.eval(Compiler.java:5349) and I saw a similar problem with builds that referred to libraries built with different versions of Clojure. How do people deal with this? How can one simultaneously use two libraries which have hardwired dependencies on two different Clojure versions, each of which might be mutually incompatible? What's the community protocol around locally installing Clojure 1.2, and adding that as a dependency for a published library? What's the right way to get lein itself to use a recent Clojure build, rather than the version with which it ships? Thoughts -- and answers! -- welcome. Thanks, -R -- 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 Note that posts from new members are moderated - please be patient with your first post. 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