Common Lisp, Clojure and Evolution
adrianmouat.com
adrianmouat.com
(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.
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. :)
And yes, that flaw is icky; one of the few in Hickey's otherwise excellent track-record in good taste.
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.
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}I will announce this great news to a few of my closest friends :-)
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.