3 ms·
The problem is not the complexity of the api but how verbose it is. Having to type (setf (gethash "foo" *hash*) "OH HAI") just for something as trivial as
by newt0311 18y ago
The problem is not the complexity of the api but how verbose it is. Having to type
(setf (gethash "foo" *hash*) "OH HAI")
just for something as trivial as "hash['foo'] = "OH HAI"" is really too much work and a significant disincentive to using hash tables.
- jimbokun 18y agoIn Arc that's (= (*hash* "foo") "OH HAI")
- KirinDave 18y agoAnd in PLT Scheme it's (hash-set! *hash* "foo" "OH HAI")
- KirinDave 18y agoSetf is the generic form (and it's pretty cool how setf works). There are more succinct ways of putting it. But you need to remember that functional languages discourage that kind of mutable state. It should be no surprise that some things (like assignment) are more awkward in that environment. It's a tradeoff.
- newt0311 18y agoYes but lisp is not a functional language and (to my incomplete knowledge of CL) setf is the only way to modify the hash table. Thus, people have to use that form if they want to use hash tables.
- pmjordan 18y agoIn fairness you could define a function that did it for you: (defun assoc (table key val) (setf (gethash key table) val) table) or something like that. (this is from memory, hope it's right) You can then let it take a variable number of arguments to make it even more concise. (yes, I've stolen the assoc semantics from Clojure, minus the pure functional aspect)
- newt0311 18y agoWell, a macro but yes. Still, if you have to write a macro for something as trivial as that, that in itself is a problem. Especially when other people start reading your code.
- pmjordan 18y agoWhy would you need a macro? Surely a function will suffice. Whether or not this is acceptable is a matter of taste I guess. I couldn't get on with CL either and was glad to find Clojure, which is now my language of choice.
- silentbicycle 18y agoAnd especially since people just learning the language aren't going to know how yet.
- vikram 18y agoLast project I worked on had 9154 lines of lisp code out of which 4800 lines are utilities, that I've accumulated and written. The utilities cover everything from hash, list, string, files, function, a simple version of prolog, some algorithms like bloomfilter, suffix-tree, a simple bayesian filter implementation and a lot of stuff makes writing code easier. So it's pretty normal to have a large set of utilities that you prefer. It sort of ensures that the code doesn't become to large. I use (hput hash key value) and (hget hash key) a couple of functions, which I have. So it's a bit verbose than hash[key] = value or hash[key]. But it lets me write stuff like... (defexample cineworld-cinema-page (:record :cinema-listing (:name "ENFIELD") (:record-loop :film (:name "BEVERLY HILLS CHIHUAHUA" "BRIDE WARS") (:director "Raja Gosnell" "Gary Winick") (:starring "Andy Garcia, Drew Barrymore, Piper Perabo, George Lopez, Jamie Lee Curtis" "Anne Hathaway, Kate Hudson, Candice Bergen") (:record-loop :date (:day "Mon 26 Jan" "Tue 27 Jan") (:record-loop :time (:listing "11:10" "13:30"))))) "http://www.cineworld.co.uk/cinemas/22") I wrote the code that reads that defexample macro and generates the data from it in 2 days. When I started I had no idea what the grammar was going to look like and how I was going to accomplish any of the details.
- KirinDave 18y agoUh, why isn't lisp a functional language? True, it is not pure and side-effect free the way Haskell is, but that hardly disqualifies it. I mean, OCaml is clearly and widely regarded as a functional language, and it has nearly all the features that Lisp has, including a bundled OO syntax, side-effect IO, and mutable data structures.
- jrockway 18y agoSeriously? This is a price I'm willing to pay for the symmetry setf buys me. In languges with = for assignment, you are stuck with what the language gives you. In Lisp, you are one "defsetf" away from perfect symmetry between reads and writes. In addition, usually you are going to hide the hash-table. Instead of accessing it directly, you will probably have an interface like: (defvar *customer-cache* (make-hash-table :test equal)) (defmethod add-customer ((customer customer)) (cache-customer customer) (write-customer-to-database customer)) (defmethod cache-customer ((customer customer)) (setf (gethash (name customer) *customer-cache*) customer)) (defmethod get-customer-by-name ((name string)) (let ((maybe-customer (gethash name *customer-cache*))) (if maybe-customer maybe-customer (let ((c (get-customer-from-database-by-name name))) (cache-customer c) c)))) By the time you have more than a one-line example, the length of gethash is irrelevant. You are using your own "API" now: (add-customer (make-customer :name "jrockway" :email "jon@jrock.us")) (get-customer-by-name "jrockway") #<CUSTOMER JROCKWAY {10027D1401}>