Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Common Lisp, Clojure and Evolution (adrianmouat.com)
70 points by amouat on Feb 27, 2011 | hide | past | favorite | 13 comments


Clojure struct constructor needs keywords badly. Right now it's position-dependent and only way to know what each sub-expression is doing is to look up the definition of the structure.

  (struct person  6.3 63 63)
What do the magic numbers mean? Dunno, you need to look up defstruct definition. In Common Lisp, it's:

  (make-person :height 6.3 :age 63 :weight-in-kg 63)  
                         ;; or better :weight (kg 63)
Then

"Clojure doesn’t have the parse-integer function, but I was quickly able to implement something that did the job by calling out to the Java parseInt method."

This has to be remedied. You need to have native control over basic reading/writing; don't offshore that to another language, even one your language is implemented on-top of.

I agree with the sentiment against ASH (Arithmetic-SHift); seriously, division/multiplication as 2^N shifts is a performance hack, and a useless one at that (smart compilers already do this, and stupid ones are bytecode compilers.)

Common Lisp already has about 9 division operators (yes, NINE) and it would have been a good opportunity to introduce them and their various uses. They are: /, floor, ffloor, ceiling, fceiling, truncate, ftruncate, round, fround -- for integers and floats respectively[1], along with MOD and REM

[1] excellent candidates for removal in future CL with CLOS-based type hierarchy; type-dispatch ftw! With ML-style type annotations it would even be feasible to do type hints inline, like (values (/@double-float 22 7) (/@int 22 7)) using @ because colon is a package separator.


First of all, Clojure has struct-map, which supports keywords, much like default Common Lisp struct constructors.

Second, Clojure's defstruct is on its way out. defrecord provides similar functionality with far better performance. By default, however, it does have the positional-arguments-only flaw. My personal favorite workaround is a small macro from this post: http://groups.google.com/group/clojure/msg/5206fac13144ea99

No comment about numerical operations in Clojure: it's a sensitive topic. :)


Even the manual recommends records in lieu of struct-map.

And yes, that flaw is icky; one of the few in Hickey's otherwise excellent track-record in good taste.


The manual? What's the manual?


Here: http://clojure.org/data_structures, see the entry for StructMaps. The page on datatypes* also implies heavily that structs have been phased out in favor of records, as no reason to use structs over records is presented.

* http://clojure.org/datatypes


The defrecord constructor-by-map feature is actively being worked on for version 1.3.


Christophe Grand pointed out in the comments that a plain map should be used instead of a struct, so your example in Clojure would be: {:height 6.3 :age 63 :weight-in-kg 63}


That works in the short term, but beyond that, Clojure will need to resolve that issue.

Records are not the same thing as hash-tables. A record, or struct, is a single unit value, while a hash-table, or map, is an aggregate container. There is an implicit contract in place; a record is guaranteed to have JUST the fields it's defined to have, while a map can grow at run time (are you going to test for the fields you want and ignore the rest? quack quack! you can't add fields to a record at runtime, so the two are NOT interchangeable. Equality is a transitive relation, while duck-typing is not.)

A record is a generalization of the concept of "value" beyond data types immediately representable by machine. While a hash-table is a generalization of arrays, an aggregate of values, addressable by an index (hash-tables remedy the silly assumption that an index must be of an integral value.)

To give an analogy; it's like asking what's the best way to group a bunch of papers (folder, envlope, binder) and then hearing someone suggest "bookshelf!".

Again, OK short-term, but stinks. Fix the structs; even C has dot and arrow notations, making the field names clear.


Records and structs can grow at runtime (insofar as immutable data structures grow).

    user> (defrecord Foo [x])
    user.Foo
    user> (assoc (Foo. 1) :y 2)
    #:user.Foo{:x 1, :y 2}

    user> (defstruct foo :x)
    #'user/foo
    user> (assoc (struct-map foo :x 1) :y 2)
    {:x 1, :y 2}


Well, what do you know, Clojure records and hash-tables are equal (strongly.)

I will announce this great news to a few of my closest friends :-)


Almost. Record types are checked as part of full equality. So record Foo{:x 1} is not equal to Bar{:x 1} or to {:x 1}.


Almost. Record types are checked as part of Clojure's "=", but not as part of Java's ".equals". See [1] and linked material. This means that Foo{:x 1} and Bar{:x 1} will collide in sets and as map keys (of Clojure or Java varieties). This seems a bit icky to me, but seems to be intentional.

[1] http://dev.clojure.org/jira/browse/CLJ-736


Records also provide better performance than hash tables for their defined keys.

You can think of them as a Java class that has certain fields (it's named fields) and also implements the Map interface for additional expandability. Records provide "accessor" methods for their named fields that provide bare-metal JVM performance.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: