[alexandria-devel] [PATCH] lazy-evaluate the default value in ENSURE-GETHASH
I'm using a hash-table as a cache, and had a problem with ensure-gethash. Some example code / output: CL-USER> (let ((h (make-hash-table))) (alexandria:ensure-gethash :x h (progn (format T "expensive computation~%") 1)) (alexandria:ensure-gethash :x h (progn (format T "expensive computation~%") 1))) expensive computation expensive computation 1 T CL-USER> This patch (created using git format-patch origin/master) converts ENSURE-GETHASH to a macro that only evaluates the default if we get to the setf branch. Has a check to create and call a lambda if the default value looks complicated (using CONSTANTP). After applying my patch, here's the output: CL-USER> (let ((h (make-hash-table))) (alexandria:ensure-gethash :x h (progn (format T "expensive computation~%") 1)) (alexandria:ensure-gethash :x h (progn (format T "expensive computation~%") 1))) expensive computation 1 T CL-USER> Thoughts? Thanks, -- Ryan Davis Acceleration.net Director of Programming Services 2831 NW 41st street, suite B Gainesville, FL 32606 Office: 352-335-6500 x 124 Fax: 352-335-6506
On Wed, Dec 21, 2011 at 7:30 PM, Ryan Davis <ryan@acceleration.net> wrote:
This patch (created using git format-patch origin/master) converts ENSURE-GETHASH to a macro that only evaluates the default if we get to the setf branch. Has a check to create and call a lambda if the default value looks complicated (using CONSTANTP). [...] Thoughts?
I'd like to see this in alexandria, as it is a very common idiom for me. -Hans
On 21 December 2011 20:30, Ryan Davis <ryan@acceleration.net> wrote:
I'm using a hash-table as a cache, and had a problem with ensure-gethash. Some example code / output:
I must be missing something. Why the CONSTANTP and LAMBDA instead of (defmacro ensure-gethash (key hash-table &optional default) "Like GETHASH, but if KEY is not found in the HASH-TABLE saves the DEFAULT under key before returning it. Secondary return value is true if key was already in the table." `(multiple-value-bind (value ok) (gethash ,key ,hash-table) (if ok (values value ok) (values (setf (gethash ,key ,hash-table) ,default) nil)))) ? Cheers, -- nikodemus
No, you're not missing anything, your version is better. I just didn't think that through. I was combining a similar function from a personal utils library, and my macro used lambdas to pass the default value to a driver function. I also recently learned about constantp and just got excited :). Thanks, Ryan Davis Acceleration.net Director of Programming Services 2831 NW 41st street, suite B Gainesville, FL 32606 Office: 352-335-6500 x 124 Fax: 352-335-6506 On Friday, December 30, 2011 12:41:12 PM, Nikodemus Siivola wrote:
On 21 December 2011 20:30, Ryan Davis <ryan@acceleration.net> wrote:
I'm using a hash-table as a cache, and had a problem with ensure-gethash. Some example code / output:
I must be missing something. Why the CONSTANTP and LAMBDA instead of
(defmacro ensure-gethash (key hash-table &optional default) "Like GETHASH, but if KEY is not found in the HASH-TABLE saves the DEFAULT under key before returning it. Secondary return value is true if key was already in the table." `(multiple-value-bind (value ok) (gethash ,key ,hash-table) (if ok (values value ok) (values (setf (gethash ,key ,hash-table) ,default) nil))))
?
Cheers,
-- nikodemus
On Tue, Jan 3, 2012 at 3:25 PM, Ryan Davis <ryan@acceleration.net> wrote:
I also recently learned about constantp and just got excited :).
Talking about constantp: it takes as arguments: form &optional environment. Constantness can depend on the environment, e.g. if the form is (m) and its definition is like: (defmacro m (&environment env) (if (foo-p env) :constant-form (non-constant-form))) Therefore you should always pass on environment within macros, so instead of: (defmacro ensure-gethash (key hash-table &optional default) `(... ,(if (constantp default) ..))) use: (defmacro ensure-gethash (key hash-table &optional default &environment env) `(... ,(if (constantp default env) ..))) - Willem
participants (4)
-
Hans Hübner
-
Nikodemus Siivola
-
Ryan Davis
-
Willem Broekema