The following patch adds a :COPY-FN &key arg to COPY-HASH-TABLE which defaults to CL:IDENTITY.
This way, you can specify if you want a shallow copy (default), or a customized one which is possibly deep to some arbitrary level.
-T.
On Mar 10, 2008, at 14:20 , Tobias C. Rittweiler wrote:
The following patch adds a :COPY-FN &key arg to COPY-HASH-TABLE which defaults to CL:IDENTITY.
Why not this?
(defun copy-hash-table (table &key key ...) ... - (setf (gethash k copy) v)) + (setf (gethash k copy) (if key (funcall key v) v)) ...)
Also, I'd rather have other parameters get their default values when they are NIL, in the cases when it makes sense. E.g., with the above I can do
(defun foo (&key key) (copy-hash-table *table* :key key))
without having to worry about the default values.
Cheers, Michael
Michael Weber michaelw+alexandria@foldr.org writes:
On Mar 10, 2008, at 14:20 , Tobias C. Rittweiler wrote:
The following patch adds a :COPY-FN &key arg to COPY-HASH-TABLE which defaults to CL:IDENTITY.
Why not this?
(defun copy-hash-table (table &key key ...) ...
(setf (gethash k copy) v))
...)(setf (gethash k copy) (if key (funcall key v) v))
Also, I'd rather have other parameters get their default values when they are NIL, in the cases when it makes sense. E.g., with the above I can do
(defun foo (&key key) (copy-hash-table *table* :key key))
without having to worry about the default values.
I agree; I'll send an updated patch which will also add a test case to tests.lisp!
-T.
"Tobias C. Rittweiler" tcr@freebits.de writes:
I agree; I'll send an updated patch which will also add a test case to tests.lisp!
-T.
On Mar 10, 2008, at 15:42 , Tobias C. Rittweiler wrote:
+(defun copy-hash-table (table &key copy-fn test size
rehash-size rehash-threshold)
- "Returns a copy of hash table TABLE, with the same keys and values
as the TABLE. The copy has the same properties as the original, unless -overridden by the keyword arguments." +overridden by the keyword arguments.
+The values are copied by calling COPY-FN which defaults to CL:IDENTITY; +thus a shallow copy is returned by default."
- (setf copy-fn (or copy-fn 'identity))
I'd really rather see :key there instead of :copy-fn. Reason: it's in line with other CL functions, and it can be used that way, e.g.: (copy-hash-table *table* :key #'accessor)
That there is copying involved is rather secondary.
Also, I find :copy-fn ugly in comparison to :key, but YMMV.
M/
Michael Weber michaelw+alexandria@foldr.org writes:
I'd really rather see :key there instead of :copy-fn. Reason: it's in line with other CL functions, and it can be used that way, e.g.: (copy-hash-table *table* :key #'accessor)
That there is copying involved is rather secondary.
Also, I find :copy-fn ugly in comparison to :key, but YMMV.
I personally do not care much. Attached is a patch that calls it :KEY.
-T.
On Fri, Mar 14, 2008 at 1:59 PM, Attila Lendvai attila.lendvai@gmail.com wrote:
Also, I find :copy-fn ugly in comparison to :key, but YMMV.
I personally do not care much. Attached is a patch that calls it :KEY.
pushed, thanks!
Sorry for coming in late on this. I'm not sure I like this deep copying stuff at all.
All copying functions except COPY-TREE and COPY-ALIST functions in CL are shallow, and neither :COPY-FN nor :KEY is very documentative as an argument name.
What's the use-case for this?
Cheers,
-- Nikodemus
"Nikodemus Siivola" nikodemus@random-state.net writes:
All copying functions except COPY-TREE and COPY-ALIST functions in CL are shallow, and neither :COPY-FN nor :KEY is very documentative as an argument name.
What's the use-case for this?
What's the use-case of COPY-HASH-TABLE itself?
I personally have needed it in two cases:
a) "the following code analyzes the hash-table in some possibly destructive way; I'm interested in the result of the analysis."
b) "the following codes frob the hash-table possibly destructively; I'm possibly interested in the difference between the original and the frobbed version."
In case a) the analysis is sometimes not about the aggregate data structure stored in the hash-table, but only about the content of a slot of that data structure. So, when copying the hash-table, we only KEY what's really needed (either by giving a pointer to the original thing, or by making a copy of it) --- rationale: The analysis sees only what it needs, so there's less opportunity for corruption.
In case b): If the code frobs destructively, the destructive operation is often not only restricted to the hash-table per se, but also to the data structures contained in the hash-table.
Notice that COPY-HASH-TABLE is still shallow by default. It's just that hash-tables are used in more complex situations, justifying a bit more flexibility.
-T.
On Fri, Mar 14, 2008 at 3:51 PM, Tobias C. Rittweiler tcr@freebits.de wrote:
In case b): If the code frobs destructively, the destructive operation is often not only restricted to the hash-table per se, but also to the data structures contained in the hash-table.
Notice that COPY-HASH-TABLE is still shallow by default. It's just that hash-tables are used in more complex situations, justifying a bit more flexibility.
This is obviously a question of taste, but IMO in this case the deep copying should be done by the frobber, not the copy-hash-table operation. ...but my own main objection is that it is not too obvious what :KEY means there.
Perhaps you might be better served with MAP-HASH-TABLE, which maps into a new hash-table? Something like this (untested), maybe:
(defun map-hash-table (function table &rest more &key test size rehash-size rehash-threshold) "Calls FUNCTION with every key and value in hash-table TABLE, and saves the returned value under the same key in a new hash-table. Finally returns the new hash-table. The new table has the same properties as the original, unless overridden by the keyword arguments. Implementation specific hash-table properties are not copied by default, but can be specified using keywords." (setf test (or test (hash-table-test table)) size (or size (hash-table-size table)) rehash-size (or rehash-size (hash-table-size table)) rehash-threshold (or rehash-threshold (hash-table-rehash-threshold table))) (let ((real-function (ensure-function function)) (copy (apply #'make-hash-table :test test :size size :rehash-size rehash-size :rehash-threshold rehash-threshold more))) (maphash (lambda (k v) (setf (gethash k copy) (funcall real-function k v))) table) copy))
(My use-cases for COPY-HASH-TABLE are mainly for debugging: grab a copy of an application internal hash-table at a certain point in time, and then poke at it at leisure.)
Cheers,
-- Nikodemus
"Nikodemus Siivola" nikodemus@random-state.net writes:
Perhaps you might be better served with MAP-HASH-TABLE, which maps into a new hash-table? Something like this (untested), maybe:
I can see this being the better choice. I'll make the necessary changes.
-T.
"Tobias C. Rittweiler" tcr@freebits.de writes:
"Nikodemus Siivola" nikodemus@random-state.net writes:
Perhaps you might be better served with MAP-HASH-TABLE, which maps into a new hash-table? Something like this (untested), maybe:
I can see this being the better choice. I'll make the necessary changes.
This can finally be pulled from
alexandria-devel@common-lisp.net