--- a/ac.scm 2009-12-21 10:18:00.000000000 -0500
+++ b/ac.scm 2009-12-21 11:21:21.000000000 -0500
@@ -632,6 +632,19 @@
; default vals with them. To make compatible with existing written tables,
; just use an atom or 3-elt list to keep the default.
+(define table-vivifier (make-hash-table 'weak))
+
+(define (ar-table-get fn args)
+ (ar-nill
+ (or (hash-table-get fn
+ (car args)
+ (if (pair? (cdr args)) (cadr args) #f))
+ (let ((vivifier (hash-table-get table-vivifier fn #f)))
+ (and vivifier
+ (let ((val (vivifier)))
+ (hash-table-put! fn (car args) val)
+ val))))))
+
(define (ar-apply fn args)
(cond ((procedure? fn)
(apply fn args))
@@ -639,10 +652,7 @@
(list-ref fn (car args)))
((string? fn)
(string-ref fn (car args)))
- ((hash-table? fn)
- (ar-nill (hash-table-get fn
- (car args)
- (if (pair? (cdr args)) (cadr args) #f))))
+ ((hash-table? fn) (ar-table-get fn args))
; experiment: means e.g. [1] is a constant fn
; ((or (number? fn) (symbol? fn)) fn)
; another possibility: constant in functional pos means it gets
@@ -1064,7 +1074,10 @@
(xdef table (lambda args
(let ((h (make-hash-table 'equal)))
- (if (pair? args) ((car args) h))
+ (if (and (pair? args) (not (ar-false? (car args))))
+ ((car args) h))
+ (if (and (pair? args) (pair? (cdr args)))
+ (hash-table-put! table-vivifier h (cadr args)))
h)))
;(xdef table (lambda args
Inspired by Perl’s autovivification feature, this hack allows new values to be automatically created in a table when a lookup doesn’t find the key already present.
In Perl, the kind of value to create is determined by syntax. Since in Arc a list reference vs. a table reference etc. has the same syntax, we’ll instead specify a function to be called to create the new value, if a key isn’t yet in a table.
arc> (= x (table nil (fn () 0))) #hash()
arc> (++ x!a) 1
arc> x #hash((a . 1))
arc> (= y (table nil (fn () (table)))) #hash()
arc> (set y!a!b) t
arc> y #hash((a . #hash((b . t))))
Unlike having a default value for the table, the vivified value is always stored in the table.
arc> (= z (table nil (fn () 0))) #hash()
arc> z!a 0
arc> z #hash((a . 0))
This means it doesn't make sense to use this for tables where you want to be able to check whether a value is already in the table or not.
Using the hackinator:
$ hack \
ycombinator.com/arc/arc3.1.tar \
awwx.ws/table-vivifier0.patchThis patch is in the public domain. The combination of this patch and Arc may be redistributed or modified under the same terms as Arc itself.