Re: Feature idea: meta-macros

2010-09-15 Thread Richard Newman
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?

2010-09-08 Thread Richard Newman
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.

2010-06-24 Thread Richard Newman

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

2010-06-21 Thread Richard Newman

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

2010-06-20 Thread Richard Newman

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

2010-06-18 Thread Richard Newman
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

2010-06-17 Thread Richard Newman
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

2010-06-17 Thread Richard Newman
... 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

2010-06-03 Thread Richard Newman

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

2010-05-30 Thread Richard Newman

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

2010-05-09 Thread Richard Newman

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

2010-05-06 Thread Richard Newman

(+ 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

2010-04-28 Thread Richard Newman

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

2010-04-27 Thread Richard Newman

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

2010-04-27 Thread Richard Newman

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

2010-04-24 Thread Richard Newman

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

2010-04-23 Thread Richard Newman

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

2010-04-18 Thread Richard Newman
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

2010-04-05 Thread Richard Newman

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

2010-04-05 Thread Richard Newman
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

2010-03-31 Thread Richard Newman

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

2010-03-28 Thread Richard Newman

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

2010-03-28 Thread Richard Newman

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

2010-03-28 Thread Richard Newman

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

2010-03-25 Thread Richard Newman

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

2010-03-25 Thread Richard Newman

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

2010-03-21 Thread Richard Newman
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

2010-03-18 Thread Richard Newman

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?

2010-03-17 Thread Richard Newman
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?

2010-03-17 Thread Richard Newman
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

2010-03-14 Thread Richard Newman

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?

2010-03-12 Thread Richard Newman
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

2010-03-11 Thread Richard Newman

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?

2010-03-10 Thread Richard Newman

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?

2010-03-10 Thread Richard Newman

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?

2010-03-09 Thread Richard Newman

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

2010-03-08 Thread Richard Newman

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

2010-03-03 Thread Richard Newman

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

2010-03-01 Thread Richard Newman

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

2010-03-01 Thread Richard Newman

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.

2010-03-01 Thread Richard Newman

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

2010-02-28 Thread Richard Newman

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

2010-02-28 Thread Richard Newman

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.

2010-02-28 Thread Richard Newman

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

2010-02-28 Thread Richard Newman

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

2010-02-23 Thread Richard Newman
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

2010-02-21 Thread Richard Newman
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

2010-02-19 Thread Richard Newman

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

2010-02-18 Thread Richard Newman

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

2010-02-17 Thread Richard Newman

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

2010-02-17 Thread Richard Newman

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

2010-02-16 Thread Richard Newman

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

2010-02-16 Thread Richard Newman

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

2010-02-15 Thread Richard Newman

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?

2010-02-14 Thread Richard Newman

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

2010-02-14 Thread Richard Newman

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?

2010-02-14 Thread Richard Newman

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?

2010-02-13 Thread Richard Newman

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

2010-02-11 Thread Richard Newman

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 ... ?

2010-02-11 Thread Richard Newman

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

2010-02-11 Thread Richard Newman
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

2010-02-08 Thread Richard Newman
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

2010-02-05 Thread Richard Newman
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

2010-02-05 Thread Richard Newman

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

2010-02-04 Thread Richard Newman

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?

2010-02-04 Thread Richard Newman
* 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?

2010-02-04 Thread Richard Newman
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?

2010-02-04 Thread Richard Newman
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?

2010-02-04 Thread Richard Newman
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?

2010-02-04 Thread Richard Newman

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

2010-02-02 Thread Richard Newman

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

2010-02-01 Thread Richard Newman

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 ...) ?

2010-02-01 Thread Richard Newman

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 ...) ?

2010-02-01 Thread Richard Newman

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 ...) ?

2010-02-01 Thread Richard Newman

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?

2010-02-01 Thread Richard Newman

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?

2010-01-28 Thread Richard Newman

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?

2010-01-28 Thread Richard Newman

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?

2010-01-28 Thread Richard Newman

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

2010-01-28 Thread Richard Newman

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?

2010-01-28 Thread Richard Newman
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?

2010-01-28 Thread Richard Newman

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

2010-01-28 Thread Richard Newman

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

2010-01-27 Thread Richard Newman

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

2010-01-24 Thread Richard Newman
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

2010-01-24 Thread Richard Newman

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

2010-01-24 Thread Richard Newman

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

2010-01-23 Thread Richard Newman
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

2010-01-23 Thread Richard Newman
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

2010-01-22 Thread Richard Newman

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

2010-01-22 Thread Richard Newman
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

2010-01-22 Thread Richard Newman

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

2010-01-22 Thread Richard Newman

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

2010-01-22 Thread Richard Newman

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?

2010-01-22 Thread Richard Newman

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

2010-01-22 Thread Richard Newman
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

2010-01-22 Thread Richard Newman

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

2010-01-22 Thread Richard Newman
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?

2010-01-21 Thread Richard Newman

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

2010-01-21 Thread Richard Newman

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


  1   2   3   4   >