* Comparing hash table objects @ 2022-06-08 8:41 Ihor Radchenko 2022-06-08 8:51 ` Andreas Schwab 2023-05-15 5:56 ` bug#63513: [PATCH] Make persist-defvar work with records and hash tables Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 2 replies; 44+ messages in thread From: Ihor Radchenko @ 2022-06-08 8:41 UTC (permalink / raw) To: emacs-devel Hello, Is there any way to compare objects containing hash tables for equality? I have a struct that is created like (list 'type (make-hash-table)) With hash table later populated with some key:value pairs. I expect two structs like the above to be comparable via equal: (equal (list 'type (make-hash-table)) (list 'type (make-hash-table))) ;; => t However, running the above code gives nil. Is the above behavior intentional? Best, Ihor ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Comparing hash table objects 2022-06-08 8:41 Comparing hash table objects Ihor Radchenko @ 2022-06-08 8:51 ` Andreas Schwab 2022-06-08 9:17 ` Ihor Radchenko 2023-05-15 5:56 ` bug#63513: [PATCH] Make persist-defvar work with records and hash tables Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 1 sibling, 1 reply; 44+ messages in thread From: Andreas Schwab @ 2022-06-08 8:51 UTC (permalink / raw) To: Ihor Radchenko; +Cc: emacs-devel On Jun 08 2022, Ihor Radchenko wrote: > Is there any way to compare objects containing hash tables for equality? Hash tables are only equal if eq. -- Andreas Schwab, SUSE Labs, schwab@suse.de GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE 1748 E4D4 88E3 0EEA B9D7 "And now for something completely different." ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Comparing hash table objects 2022-06-08 8:51 ` Andreas Schwab @ 2022-06-08 9:17 ` Ihor Radchenko 2022-06-10 22:45 ` Richard Stallman 0 siblings, 1 reply; 44+ messages in thread From: Ihor Radchenko @ 2022-06-08 9:17 UTC (permalink / raw) To: Andreas Schwab; +Cc: emacs-devel Andreas Schwab <schwab@suse.de> writes: > On Jun 08 2022, Ihor Radchenko wrote: > >> Is there any way to compare objects containing hash tables for equality? > > Hash tables are only equal if eq. This is somewhat unexpected. To clarify my problem, let me explain in more details what I am trying to achieve. Currently, I am using structs to store objects with properties: (setq obj1 (type (:key1 val1 :key2 val2 ...))) (setq obj2 (type (:key1 val1 :key2 val2 ...))) ;; the same properties With this approach, I can easily compare objects with (equal obj1 obj2), use them as hash table keys, etc. However, when the number of properties increases, :key access becomes slow because plist-get has O(N) complexity. The natural solution is using hash tables: (setq obj1 (type (make-hash-table))) (setq obj2 (type (make-hash-table))) ;; fill the hash tables with :keyN valN pairs Now, I can retrieve the :key in O(1). However, all of a sudden, I am unable to compare two objects with this new internal structure. (equal obj1 obj2) returns nil. The described behavior potentially generates a lot of room for errors. It is relatively easy to remember that different hash table objects are never equal (only equal when also eq). However, when the hash tables are hidden inside a struct, it is easy to overlook that the structs cannot be compared with equal as usual. Best, Ihor ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Comparing hash table objects 2022-06-08 9:17 ` Ihor Radchenko @ 2022-06-10 22:45 ` Richard Stallman 2022-06-11 5:52 ` Ihor Radchenko 0 siblings, 1 reply; 44+ messages in thread From: Richard Stallman @ 2022-06-10 22:45 UTC (permalink / raw) To: Ihor Radchenko; +Cc: schwab, emacs-devel [[[ To any NSA and FBI agents reading my email: please consider ]]] [[[ whether defending the US Constitution against all enemies, ]]] [[[ foreign or domestic, requires you to follow Snowden's example. ]]] It clearly can be useful to compare hash tables for equivalence of contents. I see two ways to offer that facility: * As a new function. That would be upward-compatible. * By making `equal' compare them that way. That would fit the spirit of `equal', but could break some existing uses of `equal'. -- Dr Richard Stallman (https://stallman.org) Chief GNUisance of the GNU Project (https://gnu.org) Founder, Free Software Foundation (https://fsf.org) Internet Hall-of-Famer (https://internethalloffame.org) ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Comparing hash table objects 2022-06-10 22:45 ` Richard Stallman @ 2022-06-11 5:52 ` Ihor Radchenko 2022-06-11 16:04 ` Stefan Monnier 0 siblings, 1 reply; 44+ messages in thread From: Ihor Radchenko @ 2022-06-11 5:52 UTC (permalink / raw) To: rms; +Cc: schwab, emacs-devel Richard Stallman <rms@gnu.org> writes: > It clearly can be useful to compare hash tables for equivalence > of contents. I see two ways to offer that facility: > > * As a new function. That would be upward-compatible. I have seen various variants of such function in third-party packages and just in internet search results. For example, ht-equal? from https://github.com/Wilfred/ht.el/blob/master/ht.el: (defun ht-equal? (table1 table2) "Return t if TABLE1 and TABLE2 have the same keys and values. Does not compare equality predicates." (declare (side-effect-free t)) (let ((keys1 (ht-keys table1)) (keys2 (ht-keys table2)) (sentinel (make-symbol "ht-sentinel"))) (and (equal (length keys1) (length keys2)) (--all? (equal (ht-get table1 it) (ht-get table2 it sentinel)) keys1)))) However, it will not help with the problem of comparing objects containing hash tables. Unless those obejcts also define special comparison function (which is inconvenient). > * By making `equal' compare them that way. That would fit the spirit > of `equal', but could break some existing uses of `equal'. I'd say that using `equal' on hash tables with the actual intention of comparing tables by `eq' is calling for a trouble. At least, it is misleading. Best, Ihor ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Comparing hash table objects 2022-06-11 5:52 ` Ihor Radchenko @ 2022-06-11 16:04 ` Stefan Monnier 2022-06-12 9:16 ` Ihor Radchenko 2022-06-12 23:55 ` Sam Steingold 0 siblings, 2 replies; 44+ messages in thread From: Stefan Monnier @ 2022-06-11 16:04 UTC (permalink / raw) To: Ihor Radchenko; +Cc: rms, schwab, emacs-devel > However, it will not help with the problem of comparing objects > containing hash tables. Unless those obejcts also define special > comparison function (which is inconvenient). This is an instance of a fairly general problem with Lisp's equality tests (and it's not really specific to Lisp, admittedly). Maybe a half-sane way to solve this problem is to provide a generic "equality driver" which takes an argument specifying which objects to compare for structural equality (i.e. where to keep recursing). Stefan ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Comparing hash table objects 2022-06-11 16:04 ` Stefan Monnier @ 2022-06-12 9:16 ` Ihor Radchenko 2022-06-12 23:55 ` Sam Steingold 1 sibling, 0 replies; 44+ messages in thread From: Ihor Radchenko @ 2022-06-12 9:16 UTC (permalink / raw) To: Stefan Monnier; +Cc: rms, schwab, emacs-devel Stefan Monnier <monnier@iro.umontreal.ca> writes: >> However, it will not help with the problem of comparing objects >> containing hash tables. Unless those obejcts also define special >> comparison function (which is inconvenient). > > This is an instance of a fairly general problem with Lisp's equality > tests (and it's not really specific to Lisp, admittedly). > > Maybe a half-sane way to solve this problem is to provide a generic > "equality driver" which takes an argument specifying which objects to > compare for structural equality (i.e. where to keep recursing). This might be an option. It would then help if cl-defstruct supported a default comparator setting the "equality driver" to be used by default when comparing the objects using equal. Best, Ihor ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Comparing hash table objects 2022-06-11 16:04 ` Stefan Monnier 2022-06-12 9:16 ` Ihor Radchenko @ 2022-06-12 23:55 ` Sam Steingold 2022-06-13 13:02 ` Stefan Monnier 1 sibling, 1 reply; 44+ messages in thread From: Sam Steingold @ 2022-06-12 23:55 UTC (permalink / raw) To: emacs-devel, Stefan Monnier > * Stefan Monnier <zbaavre@veb.hzbagerny.pn> [2022-06-11 12:04:46 -0400]: > >> However, it will not help with the problem of comparing objects >> containing hash tables. Unless those obejcts also define special >> comparison function (which is inconvenient). > > This is an instance of a fairly general problem with Lisp's equality > tests (and it's not really specific to Lisp, admittedly). Sadly, this is true. > Maybe a half-sane way to solve this problem is to provide a generic > "equality driver" which takes an argument specifying which objects to > compare for structural equality (i.e. where to keep recursing). The way Python does it could be a good starting point: unless a class defines __eq__ method, the comparison is Lisp eq. So, if a class has structure, it should define the comparison method. See https://docs.python.org/3/reference/datamodel.html#object.__eq__ -- Sam Steingold (http://sds.podval.org/) on Pop 22.04 (jammy) X 11.0.12101003 http://childpsy.net http://calmchildstories.com http://steingoldpsychology.com https://ij.org/ http://think-israel.org https://fairforall.org (let ((a "(let ((a %c%s%c)) (format a 34 a 34))")) (format a 34 a 34)) ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Comparing hash table objects 2022-06-12 23:55 ` Sam Steingold @ 2022-06-13 13:02 ` Stefan Monnier 2022-06-13 16:18 ` Sam Steingold 0 siblings, 1 reply; 44+ messages in thread From: Stefan Monnier @ 2022-06-13 13:02 UTC (permalink / raw) To: emacs-devel Sam Steingold [2022-06-12 19:55:08] wrote: > The way Python does it could be a good starting point: > unless a class defines __eq__ method, the comparison is Lisp eq. > So, if a class has structure, it should define the comparison method. > See https://docs.python.org/3/reference/datamodel.html#object.__eq__ Seems like the exact same way ELisp works. The problem we have right now (translated into Python) is that some people now want to add a `__eq__` method to the class `hash-table` (they argue that the lack of it was an oversight). It's easy to do what they ask for, but it breaks backward compatibility. Stefan ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Comparing hash table objects 2022-06-13 13:02 ` Stefan Monnier @ 2022-06-13 16:18 ` Sam Steingold 0 siblings, 0 replies; 44+ messages in thread From: Sam Steingold @ 2022-06-13 16:18 UTC (permalink / raw) To: emacs-devel, Stefan Monnier > * Stefan Monnier <zbaavre@veb.hzbagerny.pn> [2022-06-13 09:02:41 -0400]: > > Sam Steingold [2022-06-12 19:55:08] wrote: >> The way Python does it could be a good starting point: >> unless a class defines __eq__ method, the comparison is Lisp eq. >> So, if a class has structure, it should define the comparison method. >> See https://docs.python.org/3/reference/datamodel.html#object.__eq__ > > Seems like the exact same way ELisp works. including for user-defined classes?! > The problem we have right now (translated into Python) is that some please use ELisp terminology too for those who will want to read the sources. > people now want to add a `__eq__` method to the class `hash-table` > (they argue that the lack of it was an oversight). sounds about right. > It's easy to do what they ask for, but it breaks backward > compatibility. I would argue that code relying on `equal' being the same as `eq' for `hash-table' is a bug. Exposing such a bug might be painful, but it should be fixed anyway. Thank you for your clarifications. -- Sam Steingold (https://youtube.com/channel/UCiW5WB6K4Fx-NhhtZscW7Og) on darwin Ns 10.3.2113 http://childpsy.net http://calmchildstories.com http://steingoldpsychology.com https://ij.org/ https://ffii.org https://memri.org https://jij.org He who laughs last thinks slowest. ^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables @ 2023-05-15 5:56 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-05-15 11:31 ` Eli Zaretskii 0 siblings, 1 reply; 44+ messages in thread From: Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-15 5:56 UTC (permalink / raw) To: 63513; +Cc: Adam Porter [-- Attachment #1: Type: text/plain, Size: 964 bytes --] Hello! persist-defvar does not persist records or hash tables correctly. Here's a minimal example with a hash table: (progn (persist-defvar foo (make-hash-table :test #'equal) "docstring") (puthash 'bar t foo) (persist-save 'foo) (gethash 'bar (persist-default 'foo))) ;; Expected nil, got t This patch fixes persisting records by using copy-tree. Currently, copy-tree does not work with records (see <https://lists.gnu.org/archive/html/bug-gnu-emacs/2023-05/msg00875.html>). The following snippet will return the expected value only when both this patch and the above-linked patch are applied: (progn (cl-defstruct baz a) (persist-defvar quux (make-baz :a nil) "docstring") (setf (baz-a quux) t) (persist-save 'quux) (baz-a (persist-default 'quux))) ;; Expected nil, got t Before applying this patch, the updated values in both cases are not persisted to disk. With the patch, the updated values are persisted as expected. Best, Joseph [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Make-persist-defvar-work-with-records-and-hash-table.patch --] [-- Type: text/x-diff, Size: 1141 bytes --] From b1512983fb82b9800ab6d0d1c9ca359e1251e94a Mon Sep 17 00:00:00 2001 From: Joseph Turner <joseph@breatheoutbreathe.in> Date: Sun, 14 May 2023 22:32:16 -0700 Subject: [PATCH] Make persist-defvar work with records and hash tables Previously, when persist-defvar received a record or hash table for an initial value, updated values were not persisted. This was because the value and default value shared the same structure. --- persist.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/persist.el b/persist.el index d80943d19e..a40fc2b297 100644 --- a/persist.el +++ b/persist.el @@ -118,7 +118,9 @@ (defun persist-symbol (symbol &optional initvalue) (let ((initvalue (or initvalue (symbol-value symbol)))) (add-to-list 'persist--symbols symbol) (put symbol 'persist t) - (put symbol 'persist-default initvalue))) + (if (eq 'hash-table (type-of initvalue)) + (put symbol 'persist-default (copy-hash-table initvalue)) + (put symbol 'persist-default (copy-tree initvalue t))))) (defun persist--persistant-p (symbol) "Return non-nil if SYMBOL is a persistant variable." -- 2.40.1 ^ permalink raw reply related [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-05-15 5:56 ` bug#63513: [PATCH] Make persist-defvar work with records and hash tables Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-15 11:31 ` Eli Zaretskii 2023-05-23 20:14 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 44+ messages in thread From: Eli Zaretskii @ 2023-05-15 11:31 UTC (permalink / raw) To: Joseph Turner, Phillip Lord, Stefan Monnier; +Cc: adam, 63513 > Cc: Adam Porter <adam@alphapapa.net> > Date: Sun, 14 May 2023 22:56:20 -0700 > From: Joseph Turner via "Bug reports for GNU Emacs, > the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org> > > persist-defvar does not persist records or hash tables correctly. > > Here's a minimal example with a hash table: > > (progn > (persist-defvar foo (make-hash-table :test #'equal) "docstring") > (puthash 'bar t foo) > (persist-save 'foo) > (gethash 'bar (persist-default 'foo))) ;; Expected nil, got t > > This patch fixes persisting records by using copy-tree. Currently, > copy-tree does not work with records (see > <https://lists.gnu.org/archive/html/bug-gnu-emacs/2023-05/msg00875.html>). > The following snippet will return the expected value only when both this > patch and the above-linked patch are applied: > > (progn > (cl-defstruct baz a) > (persist-defvar quux (make-baz :a nil) "docstring") > (setf (baz-a quux) t) > (persist-save 'quux) > (baz-a (persist-default 'quux))) ;; Expected nil, got t > > Before applying this patch, the updated values in both cases are not > persisted to disk. With the patch, the updated values are persisted as > expected. Philip, any comments? ^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-05-15 11:31 ` Eli Zaretskii @ 2023-05-23 20:14 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-02 23:54 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 44+ messages in thread From: Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-05-23 20:14 UTC (permalink / raw) To: Eli Zaretskii; +Cc: adam, 63513, Stefan Monnier, Phillip Lord [-- Attachment #1: Type: text/plain, Size: 258 bytes --] The patch should now work on Emacs versions before Emacs 30. I also added tests for persisting records and hash tables. Instead of copying the updated behavior of copy-tree into persist.el, would it be more appropriate to require compat.el? Best, Joseph [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Add-test-persist-save-macro.patch --] [-- Type: text/x-diff, Size: 3379 bytes --] From 7907521e72e2e99b883912f250b7afb14cbf5e80 Mon Sep 17 00:00:00 2001 From: Joseph Turner <joseph@breatheoutbreathe.in> Date: Tue, 23 May 2023 12:57:02 -0700 Subject: [PATCH 1/5] Add test-persist-save macro --- test/persist-tests.el | 76 +++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 43 deletions(-) diff --git a/test/persist-tests.el b/test/persist-tests.el index b6645a9297..0a85b78767 100644 --- a/test/persist-tests.el +++ b/test/persist-tests.el @@ -25,51 +25,41 @@ (ert-deftest test-persist-save-only-persistant () :type 'error :exclude-subtypes t)) -(ert-deftest test-persist-save () - (with-local-temp-persist - (let ((sym (cl-gensym))) - ;; precondition - (should-not (file-exists-p (persist--file-location sym))) - (set sym 10) - (persist-symbol sym 10) - (persist-save sym) - (should t) - (should-not (file-exists-p (persist--file-location sym))) - (set sym 20) - (persist-save sym) - (should (file-exists-p (persist--file-location sym))) - (should - (string-match-p - "20" - (with-temp-buffer - (insert-file-contents (persist--file-location sym)) - (buffer-string)))) - (set sym 10) - (persist-save sym) - (should-not (file-exists-p (persist--file-location sym))) - (should-error - (persist-save 'fred))))) +(defmacro test-persist-save (init default change printed-changed) + "Test persisting symbols. +- symbol is not persisted when value is set to INIT and default + value is set to DEFAULT. +- symbol is persisted when value is changed according to CHANGE. +- persisted file contents match PRINTED-CHANGED. +- symbol is not persisted after value is set back to DEFAULT." + `(with-local-temp-persist + (let ((sym (cl-gensym))) + (should-not (file-exists-p (persist--file-location sym))) + (set sym ,init) + (persist-symbol sym ,default) + (persist-save sym) + (should t) + (should-not (file-exists-p (persist--file-location sym))) + ,change + (persist-save sym) + (should (file-exists-p (persist--file-location sym))) + (should + (string-match-p + ,printed-changed + (with-temp-buffer + (insert-file-contents (persist--file-location sym)) + (buffer-string)))) + (set sym ,default) + (persist-save sym) + (should-not (file-exists-p (persist--file-location sym)))))) -(ert-deftest test-persist-save-non-number () - "Test saving something that is not a number. +(ert-deftest test-persist-save-number () + "Test saving number." + (test-persist-save 1 1 (set sym 2) "2")) -`test-persist-save' missed " - (with-local-temp-persist - (let ((sym (cl-gensym))) - (set sym "fred") - (persist-symbol sym "fred") - (persist-save sym) - (should t) - (should-not (file-exists-p (persist--file-location sym))) - (set sym "george") - (persist-save sym) - (should (file-exists-p (persist--file-location sym))) - (should - (string-match-p - "george" - (with-temp-buffer - (insert-file-contents (persist--file-location sym)) - (buffer-string))))))) +(ert-deftest test-persist-save-string () + "Test saving string." + (test-persist-save "foo" "foo" (set sym "bar") "bar")) (ert-deftest test-persist-load () (with-local-temp-persist -- 2.40.1 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: 0002-Add-persist-hash-equal.patch --] [-- Type: text/x-diff, Size: 1460 bytes --] From 41f90ac59a26018382d1bb9153af08ce4b9423ff Mon Sep 17 00:00:00 2001 From: Joseph Turner <joseph@breatheoutbreathe.in> Date: Tue, 23 May 2023 12:52:24 -0700 Subject: [PATCH 2/5] Add persist-hash-equal See bug#63671. --- persist.el | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/persist.el b/persist.el index d80943d19e..0069273ca2 100644 --- a/persist.el +++ b/persist.el @@ -187,5 +187,22 @@ (defun persist--save-all () (add-hook 'kill-emacs-hook 'persist--save-all) +(defun persist-hash-equal (hash1 hash2) + "Return non-nil when the contents of HASH1 and HASH2 are equal. +Table values are compared using `equal' unless they are both hash +tables themselves, in which case `hash-equal' is used. +Does not compare equality predicates." + (and (= (hash-table-count hash1) + (hash-table-count hash2)) + (catch 'flag (maphash (lambda (key hash1-value) + (let ((hash2-value (gethash key hash2))) + (or (if (and (hash-table-p hash1-value) + (hash-table-p hash2-value)) + (hash-equal hash1-value hash2-value) + (equal hash1-value hash2-value)) + (throw 'flag nil)))) + hash1) + t))) + (provide 'persist) ;;; persist.el ends here -- 2.40.1 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #4: 0003-Make-persist-defvar-work-with-hash-tables.patch --] [-- Type: text/x-diff, Size: 2988 bytes --] From 53e166cb0c7c2624a5a54edafe8828d7b7edc612 Mon Sep 17 00:00:00 2001 From: Joseph Turner <joseph@breatheoutbreathe.in> Date: Tue, 23 May 2023 13:09:29 -0700 Subject: [PATCH 3/5] Make persist-defvar work with hash tables Previously, when persist-defvar received a hash table for an initial value, updated values were not persisted. --- persist.el | 16 +++++++++++----- test/persist-tests.el | 8 ++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/persist.el b/persist.el index 0069273ca2..725f2f71cf 100644 --- a/persist.el +++ b/persist.el @@ -118,7 +118,9 @@ (defun persist-symbol (symbol &optional initvalue) (let ((initvalue (or initvalue (symbol-value symbol)))) (add-to-list 'persist--symbols symbol) (put symbol 'persist t) - (put symbol 'persist-default initvalue))) + (if (hash-table-p initvalue) + (put symbol 'persist-default (copy-hash-table initvalue)) + (put symbol 'persist-default initvalue)))) (defun persist--persistant-p (symbol) "Return non-nil if SYMBOL is a persistant variable." @@ -132,9 +134,13 @@ (defun persist-save (symbol) (unless (persist--persistant-p symbol) (error (format "Symbol %s is not persistant" symbol))) - (let ((symbol-file-loc (persist--file-location symbol))) - (if (equal (symbol-value symbol) - (persist-default symbol)) + (let ((symbol-file-loc (persist--file-location symbol)) + (value (symbol-value symbol)) + (default (persist-default symbol))) + (if (if (and (hash-table-p value) + (hash-table-p default)) + (persist-hash-equal value default) + (equal value default)) (when (file-exists-p symbol-file-loc) (delete-file symbol-file-loc)) (let ((dir-loc @@ -148,7 +154,7 @@ (defun persist-save (symbol) (print-escape-control-characters t) (print-escape-nonascii t) (print-circle t)) - (print (symbol-value symbol) (current-buffer))) + (print value (current-buffer))) (write-region (point-min) (point-max) symbol-file-loc nil 'quiet)))))) diff --git a/test/persist-tests.el b/test/persist-tests.el index 0a85b78767..8a30a24e23 100644 --- a/test/persist-tests.el +++ b/test/persist-tests.el @@ -61,6 +61,14 @@ (ert-deftest test-persist-save-string () "Test saving string." (test-persist-save "foo" "foo" (set sym "bar") "bar")) +(ert-deftest test-persist-save-hash () + "Test saving hash table." + (let* ((hash (make-hash-table)) + (default (copy-hash-table hash))) + (test-persist-save hash default + (puthash 'foo "bar" (symbol-value sym)) + "#s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8125 data (foo \"bar\"))"))) + (ert-deftest test-persist-load () (with-local-temp-persist (let ((sym (cl-gensym))) -- 2.40.1 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #5: 0004-Add-persist-copy-tree.patch --] [-- Type: text/x-diff, Size: 1912 bytes --] From ccc1be590b6c7b71aaa4ee3dd3bf25184ea7c122 Mon Sep 17 00:00:00 2001 From: Joseph Turner <joseph@breatheoutbreathe.in> Date: Tue, 23 May 2023 13:43:02 -0700 Subject: [PATCH 4/5] Add persist-copy-tree The behavior of copy-tree was changed in Emacs 30. This function will ensure that persist works correctly for previous Emacs versions. --- persist.el | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/persist.el b/persist.el index 725f2f71cf..eb408b5dca 100644 --- a/persist.el +++ b/persist.el @@ -210,5 +210,34 @@ (defun persist-hash-equal (hash1 hash2) hash1) t))) + +(defun persist-copy-tree (tree &optional vectors-and-records) + "Make a copy of TREE. +If TREE is a cons cell, this recursively copies both its car and its cdr. +Contrast to `copy-sequence', which copies only along the cdrs. +With the second argument VECTORS-AND-RECORDS non-nil, this +traverses and copies vectors and records as well as conses." + (declare (side-effect-free error-free)) + (if (consp tree) + (let (result) + (while (consp tree) + (let ((newcar (car tree))) + (if (or (consp (car tree)) + (and vectors-and-records + (or (vectorp (car tree)) (recordp (car tree))))) + (setq newcar (copy-tree (car tree) vectors-and-records))) + (push newcar result)) + (setq tree (cdr tree))) + (nconc (nreverse result) + (if (and vectors-and-records (or (vectorp tree) (recordp tree))) + (copy-tree tree vectors-and-records) + tree))) + (if (and vectors-and-records (or (vectorp tree) (recordp tree))) + (let ((i (length (setq tree (copy-sequence tree))))) + (while (>= (setq i (1- i)) 0) + (aset tree i (copy-tree (aref tree i) vectors-and-records))) + tree) + tree))) + (provide 'persist) ;;; persist.el ends here -- 2.40.1 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #6: 0005-Make-persist-defvar-work-with-records.patch --] [-- Type: text/x-diff, Size: 1763 bytes --] From 4658bde147253d2f070b14c6f54300f640da063e Mon Sep 17 00:00:00 2001 From: Joseph Turner <joseph@breatheoutbreathe.in> Date: Tue, 23 May 2023 13:44:40 -0700 Subject: [PATCH 5/5] Make persist-defvar work with records Previously, when persist-defvar received a record for an initial value, updated values were not persisted. --- persist.el | 2 +- test/persist-tests.el | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/persist.el b/persist.el index eb408b5dca..39ce54bbf0 100644 --- a/persist.el +++ b/persist.el @@ -120,7 +120,7 @@ (defun persist-symbol (symbol &optional initvalue) (put symbol 'persist t) (if (hash-table-p initvalue) (put symbol 'persist-default (copy-hash-table initvalue)) - (put symbol 'persist-default initvalue)))) + (put symbol 'persist-default (persist-copy-tree initvalue t))))) (defun persist--persistant-p (symbol) "Return non-nil if SYMBOL is a persistant variable." diff --git a/test/persist-tests.el b/test/persist-tests.el index 8a30a24e23..18b8af2b89 100644 --- a/test/persist-tests.el +++ b/test/persist-tests.el @@ -69,6 +69,14 @@ (ert-deftest test-persist-save-hash () (puthash 'foo "bar" (symbol-value sym)) "#s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8125 data (foo \"bar\"))"))) +(ert-deftest test-persist-save-record () + "Test saving record." + (let* ((rec (record 'foo 'a 'b)) + (default (copy-sequence rec))) + (test-persist-save rec default + (setf (aref (symbol-value sym) 2) 'quux) + "#s(foo a quux)"))) + (ert-deftest test-persist-load () (with-local-temp-persist (let ((sym (cl-gensym))) -- 2.40.1 ^ permalink raw reply related [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-05-23 20:14 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-02 23:54 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-03 6:08 ` Eli Zaretskii 0 siblings, 1 reply; 44+ messages in thread From: Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-02 23:54 UTC (permalink / raw) To: Eli Zaretskii, Phillip Lord, Stefan Monnier, 63513, adam [-- Attachment #1: Type: text/plain, Size: 60 bytes --] I fixed the definition of persist-hash-equal, and rebased. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Add-test-persist-save-macro.patch --] [-- Type: text/x-diff, Size: 3379 bytes --] From 6ec3955a521266e0661bbd0b2a6d1984875ae1a1 Mon Sep 17 00:00:00 2001 From: Joseph Turner <joseph@breatheoutbreathe.in> Date: Tue, 23 May 2023 12:57:02 -0700 Subject: [PATCH 1/5] Add test-persist-save macro --- test/persist-tests.el | 76 +++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 43 deletions(-) diff --git a/test/persist-tests.el b/test/persist-tests.el index b6645a9297..0a85b78767 100644 --- a/test/persist-tests.el +++ b/test/persist-tests.el @@ -25,51 +25,41 @@ (ert-deftest test-persist-save-only-persistant () :type 'error :exclude-subtypes t)) -(ert-deftest test-persist-save () - (with-local-temp-persist - (let ((sym (cl-gensym))) - ;; precondition - (should-not (file-exists-p (persist--file-location sym))) - (set sym 10) - (persist-symbol sym 10) - (persist-save sym) - (should t) - (should-not (file-exists-p (persist--file-location sym))) - (set sym 20) - (persist-save sym) - (should (file-exists-p (persist--file-location sym))) - (should - (string-match-p - "20" - (with-temp-buffer - (insert-file-contents (persist--file-location sym)) - (buffer-string)))) - (set sym 10) - (persist-save sym) - (should-not (file-exists-p (persist--file-location sym))) - (should-error - (persist-save 'fred))))) +(defmacro test-persist-save (init default change printed-changed) + "Test persisting symbols. +- symbol is not persisted when value is set to INIT and default + value is set to DEFAULT. +- symbol is persisted when value is changed according to CHANGE. +- persisted file contents match PRINTED-CHANGED. +- symbol is not persisted after value is set back to DEFAULT." + `(with-local-temp-persist + (let ((sym (cl-gensym))) + (should-not (file-exists-p (persist--file-location sym))) + (set sym ,init) + (persist-symbol sym ,default) + (persist-save sym) + (should t) + (should-not (file-exists-p (persist--file-location sym))) + ,change + (persist-save sym) + (should (file-exists-p (persist--file-location sym))) + (should + (string-match-p + ,printed-changed + (with-temp-buffer + (insert-file-contents (persist--file-location sym)) + (buffer-string)))) + (set sym ,default) + (persist-save sym) + (should-not (file-exists-p (persist--file-location sym)))))) -(ert-deftest test-persist-save-non-number () - "Test saving something that is not a number. +(ert-deftest test-persist-save-number () + "Test saving number." + (test-persist-save 1 1 (set sym 2) "2")) -`test-persist-save' missed " - (with-local-temp-persist - (let ((sym (cl-gensym))) - (set sym "fred") - (persist-symbol sym "fred") - (persist-save sym) - (should t) - (should-not (file-exists-p (persist--file-location sym))) - (set sym "george") - (persist-save sym) - (should (file-exists-p (persist--file-location sym))) - (should - (string-match-p - "george" - (with-temp-buffer - (insert-file-contents (persist--file-location sym)) - (buffer-string))))))) +(ert-deftest test-persist-save-string () + "Test saving string." + (test-persist-save "foo" "foo" (set sym "bar") "bar")) (ert-deftest test-persist-load () (with-local-temp-persist -- 2.41.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: 0002-Add-persist-hash-equal.patch --] [-- Type: text/x-diff, Size: 1475 bytes --] From 1f6fae3a9799dbb58b742095480917c2e3b99a7f Mon Sep 17 00:00:00 2001 From: Joseph Turner <joseph@breatheoutbreathe.in> Date: Sat, 2 Sep 2023 16:52:31 -0700 Subject: [PATCH 2/5] Add persist-hash-equal See bug#63671. --- persist.el | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/persist.el b/persist.el index d80943d19e..fd0d750161 100644 --- a/persist.el +++ b/persist.el @@ -187,5 +187,22 @@ (defun persist--save-all () (add-hook 'kill-emacs-hook 'persist--save-all) +(defun persist-hash-equal (hash1 hash2) + "Return non-nil when the contents of HASH1 and HASH2 are equal. +Table values are compared using `equal' unless they are both hash +tables themselves, in which case `persist-hash-equal' is used. +Does not compare equality predicates." + (and (= (hash-table-count hash1) + (hash-table-count hash2)) + (catch 'flag (maphash (lambda (key hash1-value) + (let ((hash2-value (gethash key hash2))) + (or (if (and (hash-table-p hash1-value) + (hash-table-p hash2-value)) + (persist-hash-equal hash1-value hash2-value) + (equal hash1-value hash2-value)) + (throw 'flag nil)))) + hash1) + t))) + (provide 'persist) ;;; persist.el ends here -- 2.41.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #4: 0003-Make-persist-defvar-work-with-hash-tables.patch --] [-- Type: text/x-diff, Size: 3100 bytes --] From ae35177b30bf1fabbc56ebf315b25a6074102201 Mon Sep 17 00:00:00 2001 From: Joseph Turner <joseph@breatheoutbreathe.in> Date: Tue, 23 May 2023 13:09:29 -0700 Subject: [PATCH 3/5] Make persist-defvar work with hash tables Previously, when persist-defvar received a hash table for an initial value, updated values were not persisted. --- persist.el | 17 ++++++++++++----- test/persist-tests.el | 8 ++++++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/persist.el b/persist.el index fd0d750161..9a0ee33a65 100644 --- a/persist.el +++ b/persist.el @@ -118,7 +118,9 @@ (defun persist-symbol (symbol &optional initvalue) (let ((initvalue (or initvalue (symbol-value symbol)))) (add-to-list 'persist--symbols symbol) (put symbol 'persist t) - (put symbol 'persist-default initvalue))) + (if (hash-table-p initvalue) + (put symbol 'persist-default (copy-hash-table initvalue)) + (put symbol 'persist-default initvalue)))) (defun persist--persistant-p (symbol) "Return non-nil if SYMBOL is a persistant variable." @@ -132,9 +134,14 @@ (defun persist-save (symbol) (unless (persist--persistant-p symbol) (error (format "Symbol %s is not persistant" symbol))) - (let ((symbol-file-loc (persist--file-location symbol))) - (if (equal (symbol-value symbol) - (persist-default symbol)) + (let* ((symbol-file-loc (persist--file-location symbol)) + (value (symbol-value symbol)) + (default (persist-default symbol)) + (value-unchanged-p (if (and (hash-table-p value) + (hash-table-p default)) + (persist-hash-equal value default) + (equal value default)))) + (if value-unchanged-p (when (file-exists-p symbol-file-loc) (delete-file symbol-file-loc)) (let ((dir-loc @@ -148,7 +155,7 @@ (defun persist-save (symbol) (print-escape-control-characters t) (print-escape-nonascii t) (print-circle t)) - (print (symbol-value symbol) (current-buffer))) + (print value (current-buffer))) (write-region (point-min) (point-max) symbol-file-loc nil 'quiet)))))) diff --git a/test/persist-tests.el b/test/persist-tests.el index 0a85b78767..8a30a24e23 100644 --- a/test/persist-tests.el +++ b/test/persist-tests.el @@ -61,6 +61,14 @@ (ert-deftest test-persist-save-string () "Test saving string." (test-persist-save "foo" "foo" (set sym "bar") "bar")) +(ert-deftest test-persist-save-hash () + "Test saving hash table." + (let* ((hash (make-hash-table)) + (default (copy-hash-table hash))) + (test-persist-save hash default + (puthash 'foo "bar" (symbol-value sym)) + "#s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8125 data (foo \"bar\"))"))) + (ert-deftest test-persist-load () (with-local-temp-persist (let ((sym (cl-gensym))) -- 2.41.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #5: 0004-Add-persist-copy-tree.patch --] [-- Type: text/x-diff, Size: 1909 bytes --] From 1b06fc7efb7339c390170e2bc26e298153221f2e Mon Sep 17 00:00:00 2001 From: Joseph Turner <joseph@breatheoutbreathe.in> Date: Tue, 23 May 2023 13:43:02 -0700 Subject: [PATCH 4/5] Add persist-copy-tree The behavior of copy-tree was changed in Emacs 30. This function will ensure that persist works correctly for previous Emacs versions. --- persist.el | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/persist.el b/persist.el index 9a0ee33a65..8eb0e7ba51 100644 --- a/persist.el +++ b/persist.el @@ -211,5 +211,33 @@ (defun persist-hash-equal (hash1 hash2) hash1) t))) +(defun persist-copy-tree (tree &optional vectors-and-records) + "Make a copy of TREE. +If TREE is a cons cell, this recursively copies both its car and its cdr. +Contrast to `copy-sequence', which copies only along the cdrs. +With the second argument VECTORS-AND-RECORDS non-nil, this +traverses and copies vectors and records as well as conses." + (declare (side-effect-free error-free)) + (if (consp tree) + (let (result) + (while (consp tree) + (let ((newcar (car tree))) + (if (or (consp (car tree)) + (and vectors-and-records + (or (vectorp (car tree)) (recordp (car tree))))) + (setq newcar (copy-tree (car tree) vectors-and-records))) + (push newcar result)) + (setq tree (cdr tree))) + (nconc (nreverse result) + (if (and vectors-and-records (or (vectorp tree) (recordp tree))) + (copy-tree tree vectors-and-records) + tree))) + (if (and vectors-and-records (or (vectorp tree) (recordp tree))) + (let ((i (length (setq tree (copy-sequence tree))))) + (while (>= (setq i (1- i)) 0) + (aset tree i (copy-tree (aref tree i) vectors-and-records))) + tree) + tree))) + (provide 'persist) ;;; persist.el ends here -- 2.41.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #6: 0005-Make-persist-defvar-work-with-records.patch --] [-- Type: text/x-diff, Size: 1763 bytes --] From afd6ea405efb1cba0ad1b1601f4af8efc796c1d7 Mon Sep 17 00:00:00 2001 From: Joseph Turner <joseph@breatheoutbreathe.in> Date: Tue, 23 May 2023 13:44:40 -0700 Subject: [PATCH 5/5] Make persist-defvar work with records Previously, when persist-defvar received a record for an initial value, updated values were not persisted. --- persist.el | 2 +- test/persist-tests.el | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/persist.el b/persist.el index 8eb0e7ba51..2f3885f80e 100644 --- a/persist.el +++ b/persist.el @@ -120,7 +120,7 @@ (defun persist-symbol (symbol &optional initvalue) (put symbol 'persist t) (if (hash-table-p initvalue) (put symbol 'persist-default (copy-hash-table initvalue)) - (put symbol 'persist-default initvalue)))) + (put symbol 'persist-default (persist-copy-tree initvalue t))))) (defun persist--persistant-p (symbol) "Return non-nil if SYMBOL is a persistant variable." diff --git a/test/persist-tests.el b/test/persist-tests.el index 8a30a24e23..18b8af2b89 100644 --- a/test/persist-tests.el +++ b/test/persist-tests.el @@ -69,6 +69,14 @@ (ert-deftest test-persist-save-hash () (puthash 'foo "bar" (symbol-value sym)) "#s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8125 data (foo \"bar\"))"))) +(ert-deftest test-persist-save-record () + "Test saving record." + (let* ((rec (record 'foo 'a 'b)) + (default (copy-sequence rec))) + (test-persist-save rec default + (setf (aref (symbol-value sym) 2) 'quux) + "#s(foo a quux)"))) + (ert-deftest test-persist-load () (with-local-temp-persist (let ((sym (cl-gensym))) -- 2.41.0 ^ permalink raw reply related [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-09-02 23:54 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-03 6:08 ` Eli Zaretskii 2023-09-04 0:29 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 44+ messages in thread From: Eli Zaretskii @ 2023-09-03 6:08 UTC (permalink / raw) To: Joseph Turner; +Cc: adam, 63513, monnier, phillip.lord > From: Joseph Turner <joseph@breatheoutbreathe.in> > Date: Sat, 02 Sep 2023 16:54:00 -0700 > > I fixed the definition of persist-hash-equal, and rebased. Thanks, but this lacks the commit log messages (see CONTRIBUTE). Also, I think the new features warrant a NEWS entry. ^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-09-03 6:08 ` Eli Zaretskii @ 2023-09-04 0:29 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-04 11:33 ` Eli Zaretskii 0 siblings, 1 reply; 44+ messages in thread From: Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-04 0:29 UTC (permalink / raw) To: Eli Zaretskii; +Cc: Adam Porter, 63513, monnier, phillip.lord [-- Attachment #1: Type: text/plain, Size: 366 bytes --] Eli Zaretskii <eliz@gnu.org> writes: > Thanks, but this lacks the commit log messages (see CONTRIBUTE). I have added commit log messages. See attached patches. > Also, I think the new features warrant a NEWS entry. Should that go in the NEWS file in the main Emacs repo? I don't see a NEWS file in either of the main or externals/persist ELPA branches. Joseph [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Add-test-persist-save-macro.patch --] [-- Type: text/x-diff, Size: 3629 bytes --] From 2ca778a44c10f11059f16ef5922cf1eff9118105 Mon Sep 17 00:00:00 2001 From: Joseph Turner <joseph@breatheoutbreathe.in> Date: Tue, 23 May 2023 12:57:02 -0700 Subject: [PATCH 1/5] Add test-persist-save macro * test/persist-tests.el (persist-test-persist-save): Consolidate logic of test-persist-save and test-persist-save-non-number. (test-persist-save-number test-persist-save-string): Simple wrappers over persist-test-persist-save --- test/persist-tests.el | 76 +++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 43 deletions(-) diff --git a/test/persist-tests.el b/test/persist-tests.el index b6645a9297..f2b04769ef 100644 --- a/test/persist-tests.el +++ b/test/persist-tests.el @@ -25,51 +25,41 @@ (ert-deftest test-persist-save-only-persistant () :type 'error :exclude-subtypes t)) -(ert-deftest test-persist-save () - (with-local-temp-persist - (let ((sym (cl-gensym))) - ;; precondition - (should-not (file-exists-p (persist--file-location sym))) - (set sym 10) - (persist-symbol sym 10) - (persist-save sym) - (should t) - (should-not (file-exists-p (persist--file-location sym))) - (set sym 20) - (persist-save sym) - (should (file-exists-p (persist--file-location sym))) - (should - (string-match-p - "20" - (with-temp-buffer - (insert-file-contents (persist--file-location sym)) - (buffer-string)))) - (set sym 10) - (persist-save sym) - (should-not (file-exists-p (persist--file-location sym))) - (should-error - (persist-save 'fred))))) +(defmacro persist-test-persist-save (init default change printed-changed) + "Test persisting symbols. +- symbol is not persisted when value is set to INIT and default + value is set to DEFAULT. +- symbol is persisted when value is changed according to CHANGE. +- persisted file contents match PRINTED-CHANGED. +- symbol is not persisted after value is set back to DEFAULT." + `(with-local-temp-persist + (let ((sym (cl-gensym))) + (should-not (file-exists-p (persist--file-location sym))) + (set sym ,init) + (persist-symbol sym ,default) + (persist-save sym) + (should t) + (should-not (file-exists-p (persist--file-location sym))) + ,change + (persist-save sym) + (should (file-exists-p (persist--file-location sym))) + (should + (string-match-p + ,printed-changed + (with-temp-buffer + (insert-file-contents (persist--file-location sym)) + (buffer-string)))) + (set sym ,default) + (persist-save sym) + (should-not (file-exists-p (persist--file-location sym)))))) -(ert-deftest test-persist-save-non-number () - "Test saving something that is not a number. +(ert-deftest test-persist-save-number () + "Test saving number." + (persist-test-persist-save 1 1 (set sym 2) "2")) -`test-persist-save' missed " - (with-local-temp-persist - (let ((sym (cl-gensym))) - (set sym "fred") - (persist-symbol sym "fred") - (persist-save sym) - (should t) - (should-not (file-exists-p (persist--file-location sym))) - (set sym "george") - (persist-save sym) - (should (file-exists-p (persist--file-location sym))) - (should - (string-match-p - "george" - (with-temp-buffer - (insert-file-contents (persist--file-location sym)) - (buffer-string))))))) +(ert-deftest test-persist-save-string () + "Test saving string." + (persist-test-persist-save "foo" "foo" (set sym "bar") "bar")) (ert-deftest test-persist-load () (with-local-temp-persist -- 2.41.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: 0002-Add-persist-equal.patch --] [-- Type: text/x-diff, Size: 1394 bytes --] From b379d8d1779e0190541ef7f8adf39dfe4d4c551a Mon Sep 17 00:00:00 2001 From: Joseph Turner <joseph@breatheoutbreathe.in> Date: Sat, 2 Sep 2023 16:52:31 -0700 Subject: [PATCH 2/5] Add persist-equal * persist.el (persist-hash-equal): Like equal, but compares hash tables also. See bug#63671 for a discussion of built-in hash table comparison. --- persist.el | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/persist.el b/persist.el index d80943d19e..a707d038cd 100644 --- a/persist.el +++ b/persist.el @@ -187,5 +187,25 @@ (defun persist--save-all () (add-hook 'kill-emacs-hook 'persist--save-all) +(defun persist-equal (a b) + "Return non-nil when the values of A and B are equal. +A and B are compared using `equal' unless they are both hash +tables. In that case, the following are compared: + +- hash table count +- hash table predicate +- values, using `persist-equal'" + (if (and (hash-table-p a) (hash-table-p b)) + (and (= (hash-table-count a) (hash-table-count b)) + (eq (hash-table-test a) (hash-table-test b)) + (catch 'done + (maphash + (lambda (key a-value) + (unless (persist-equal a-value (gethash key b (not a-value))) + (throw 'done nil))) + a) + t)) + (equal a b))) + (provide 'persist) ;;; persist.el ends here -- 2.41.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #4: 0003-Make-persist-defvar-work-with-hash-tables.patch --] [-- Type: text/x-diff, Size: 2645 bytes --] From 11194569423dcdf8778a55f59dbca8f49e8b7b37 Mon Sep 17 00:00:00 2001 From: Joseph Turner <joseph@breatheoutbreathe.in> Date: Sun, 3 Sep 2023 17:10:38 -0700 Subject: [PATCH 3/5] Make persist-defvar work with hash tables Previously, when persist-defvar received a hash table for an initial value, updated values were not persisted. * persist.el (persist-symbol): Use hash table copy as default so that the original table can be modified without modifying the default value. (persist-save): Use persist-equal to ensure that hash tables are correctly compared * test/persist-tests.el (test-persist-save-hash): Test hash tables persistence. --- persist.el | 8 +++++--- test/persist-tests.el | 8 ++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/persist.el b/persist.el index a707d038cd..7b2ab491d7 100644 --- a/persist.el +++ b/persist.el @@ -118,7 +118,9 @@ (defun persist-symbol (symbol &optional initvalue) (let ((initvalue (or initvalue (symbol-value symbol)))) (add-to-list 'persist--symbols symbol) (put symbol 'persist t) - (put symbol 'persist-default initvalue))) + (if (hash-table-p initvalue) + (put symbol 'persist-default (copy-hash-table initvalue)) + (put symbol 'persist-default initvalue)))) (defun persist--persistant-p (symbol) "Return non-nil if SYMBOL is a persistant variable." @@ -133,8 +135,8 @@ (defun persist-save (symbol) (error (format "Symbol %s is not persistant" symbol))) (let ((symbol-file-loc (persist--file-location symbol))) - (if (equal (symbol-value symbol) - (persist-default symbol)) + (if (persist-equal (symbol-value symbol) + (persist-default symbol)) (when (file-exists-p symbol-file-loc) (delete-file symbol-file-loc)) (let ((dir-loc diff --git a/test/persist-tests.el b/test/persist-tests.el index f2b04769ef..90adf1c6d6 100644 --- a/test/persist-tests.el +++ b/test/persist-tests.el @@ -61,6 +61,14 @@ (ert-deftest test-persist-save-string () "Test saving string." (persist-test-persist-save "foo" "foo" (set sym "bar") "bar")) +(ert-deftest test-persist-save-hash () + "Test saving hash table." + (let* ((hash (make-hash-table)) + (default (copy-hash-table hash))) + (persist-test-persist-save hash default + (puthash 'foo "bar" (symbol-value sym)) + "#s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8125 data (foo \"bar\"))"))) + (ert-deftest test-persist-load () (with-local-temp-persist (let ((sym (cl-gensym))) -- 2.41.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #5: 0004-Add-persist-copy-tree.patch --] [-- Type: text/x-diff, Size: 1983 bytes --] From f360f7ae53125a847c2a8d5762ca5f08d16445b9 Mon Sep 17 00:00:00 2001 From: Joseph Turner <joseph@breatheoutbreathe.in> Date: Tue, 23 May 2023 13:43:02 -0700 Subject: [PATCH 4/5] Add persist-copy-tree The behavior of copy-tree was changed in Emacs 30. This function will ensure that persist works correctly for previous Emacs versions. * persist.el (persist-copy-tree): Add copy-tree, so that records can be compared. --- persist.el | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/persist.el b/persist.el index 7b2ab491d7..93444995f2 100644 --- a/persist.el +++ b/persist.el @@ -209,5 +209,33 @@ (defun persist-equal (a b) t)) (equal a b))) +(defun persist-copy-tree (tree &optional vectors-and-records) + "Make a copy of TREE. +If TREE is a cons cell, this recursively copies both its car and its cdr. +Contrast to `copy-sequence', which copies only along the cdrs. +With the second argument VECTORS-AND-RECORDS non-nil, this +traverses and copies vectors and records as well as conses." + (declare (side-effect-free error-free)) + (if (consp tree) + (let (result) + (while (consp tree) + (let ((newcar (car tree))) + (if (or (consp (car tree)) + (and vectors-and-records + (or (vectorp (car tree)) (recordp (car tree))))) + (setq newcar (persist-copy-tree (car tree) vectors-and-records))) + (push newcar result)) + (setq tree (cdr tree))) + (nconc (nreverse result) + (if (and vectors-and-records (or (vectorp tree) (recordp tree))) + (persist-copy-tree tree vectors-and-records) + tree))) + (if (and vectors-and-records (or (vectorp tree) (recordp tree))) + (let ((i (length (setq tree (copy-sequence tree))))) + (while (>= (setq i (1- i)) 0) + (aset tree i (persist-copy-tree (aref tree i) vectors-and-records))) + tree) + tree))) + (provide 'persist) ;;; persist.el ends here -- 2.41.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #6: 0005-Make-persist-defvar-work-with-records.patch --] [-- Type: text/x-diff, Size: 2019 bytes --] From ea57e6205b10678b9c26f7dcf3704e2a7acb25a7 Mon Sep 17 00:00:00 2001 From: Joseph Turner <joseph@breatheoutbreathe.in> Date: Tue, 23 May 2023 13:44:40 -0700 Subject: [PATCH 5/5] Make persist-defvar work with records Previously, when persist-defvar received a record for an initial value, updated values were not persisted. * persist.el (persist-symbol): Set default to a copy of initvalue so when initvalue is a record, the original can be modified without modifying the default. * test/persist-tests.el: Test persist-save with a record. --- persist.el | 2 +- test/persist-tests.el | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/persist.el b/persist.el index 93444995f2..e43171459e 100644 --- a/persist.el +++ b/persist.el @@ -120,7 +120,7 @@ (defun persist-symbol (symbol &optional initvalue) (put symbol 'persist t) (if (hash-table-p initvalue) (put symbol 'persist-default (copy-hash-table initvalue)) - (put symbol 'persist-default initvalue)))) + (put symbol 'persist-default (persist-copy-tree initvalue t))))) (defun persist--persistant-p (symbol) "Return non-nil if SYMBOL is a persistant variable." diff --git a/test/persist-tests.el b/test/persist-tests.el index 90adf1c6d6..62d8501493 100644 --- a/test/persist-tests.el +++ b/test/persist-tests.el @@ -69,6 +69,14 @@ (ert-deftest test-persist-save-hash () (puthash 'foo "bar" (symbol-value sym)) "#s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8125 data (foo \"bar\"))"))) +(ert-deftest test-persist-save-record () + "Test saving record." + (let* ((rec (record 'foo 'a 'b)) + (default (copy-sequence rec))) + (persist-test-persist-save rec default + (setf (aref (symbol-value sym) 2) 'quux) + "#s(foo a quux)"))) + (ert-deftest test-persist-load () (with-local-temp-persist (let ((sym (cl-gensym))) -- 2.41.0 ^ permalink raw reply related [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-09-04 0:29 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-04 11:33 ` Eli Zaretskii 2023-09-04 15:57 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 44+ messages in thread From: Eli Zaretskii @ 2023-09-04 11:33 UTC (permalink / raw) To: Joseph Turner; +Cc: adam.porter, 63513, monnier, phillip.lord > From: Joseph Turner <joseph@breatheoutbreathe.in> > Cc: phillip.lord@russet.org.uk, monnier@iro.umontreal.ca, > 63513@debbugs.gnu.org, Adam Porter <adam.porter@47ap.net> > Date: Sun, 03 Sep 2023 17:29:22 -0700 > > > Also, I think the new features warrant a NEWS entry. > > Should that go in the NEWS file in the main Emacs repo? I don't see a > NEWS file in either of the main or externals/persist ELPA branches. I'm terribly sorry: I haven't realized this is for ELPA, I thought it was for emacs.git. My bad Please ignore what I wrote in my previous message. ^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-09-04 11:33 ` Eli Zaretskii @ 2023-09-04 15:57 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-04 17:05 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 44+ messages in thread From: Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-04 15:57 UTC (permalink / raw) To: Eli Zaretskii; +Cc: adam.porter, 63513, monnier, phillip.lord On September 4, 2023 4:33:55 AM PDT, Eli Zaretskii <eliz@gnu.org> wrote: >> From: Joseph Turner <joseph@breatheoutbreathe.in> >> Cc: phillip.lord@russet.org.uk, monnier@iro.umontreal.ca, >> 63513@debbugs.gnu.org, Adam Porter <adam.porter@47ap.net> >> Date: Sun, 03 Sep 2023 17:29:22 -0700 >> >> > Also, I think the new features warrant a NEWS entry. >> >> Should that go in the NEWS file in the main Emacs repo? I don't see a >> NEWS file in either of the main or externals/persist ELPA branches. > >I'm terribly sorry: I haven't realized this is for ELPA, I thought it >was for emacs.git. My bad Please ignore what I wrote in my previous >message. No problem! It gave me a chance to do a final editing pass. What's the next step? I would be glad for Phillip's review, if possible. ^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-09-04 15:57 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-04 17:05 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-04 22:28 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-05 15:08 ` bug#63513: [PATCH] Make persist-defvar work with records and hash tables phillip.lord 0 siblings, 2 replies; 44+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-04 17:05 UTC (permalink / raw) To: Joseph Turner; +Cc: adam.porter, Eli Zaretskii, 63513, phillip.lord Joseph Turner [2023-09-04 08:57:13] wrote: > On September 4, 2023 4:33:55 AM PDT, Eli Zaretskii <eliz@gnu.org> wrote: >>> From: Joseph Turner <joseph@breatheoutbreathe.in> >>> Cc: phillip.lord@russet.org.uk, monnier@iro.umontreal.ca, >>> 63513@debbugs.gnu.org, Adam Porter <adam.porter@47ap.net> >>> Date: Sun, 03 Sep 2023 17:29:22 -0700 >>> >>> > Also, I think the new features warrant a NEWS entry. >>> >>> Should that go in the NEWS file in the main Emacs repo? I don't see a >>> NEWS file in either of the main or externals/persist ELPA branches. >> >>I'm terribly sorry: I haven't realized this is for ELPA, I thought it >>was for emacs.git. My bad Please ignore what I wrote in my previous >>message. > > No problem! It gave me a chance to do a final editing pass. What's the next > step? I would be glad for Phillip's review, if possible. I was about to ping Phil over on https://gitlab.com/phillord/persist/ but was reminded along the way that Phil gave me write access to that repository. Could you send me the result of your final editing pass? Stefan ^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-09-04 17:05 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-04 22:28 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-05 21:06 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-05 15:08 ` bug#63513: [PATCH] Make persist-defvar work with records and hash tables phillip.lord 1 sibling, 1 reply; 44+ messages in thread From: Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-04 22:28 UTC (permalink / raw) To: Stefan Monnier; +Cc: Adam Porter, Eli Zaretskii, 63513, phillip.lord [-- Attachment #1: Type: text/plain, Size: 285 bytes --] Stefan Monnier <monnier@iro.umontreal.ca> writes: > I was about to ping Phil over on https://gitlab.com/phillord/persist/ > but was reminded along the way that Phil gave me write access to > that repository. > > Could you send me the result of your final editing pass? Here you go! [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Add-test-persist-save-macro.patch --] [-- Type: text/x-diff, Size: 3629 bytes --] From 2ca778a44c10f11059f16ef5922cf1eff9118105 Mon Sep 17 00:00:00 2001 From: Joseph Turner <joseph@breatheoutbreathe.in> Date: Tue, 23 May 2023 12:57:02 -0700 Subject: [PATCH 1/5] Add test-persist-save macro * test/persist-tests.el (persist-test-persist-save): Consolidate logic of test-persist-save and test-persist-save-non-number. (test-persist-save-number test-persist-save-string): Simple wrappers over persist-test-persist-save --- test/persist-tests.el | 76 +++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 43 deletions(-) diff --git a/test/persist-tests.el b/test/persist-tests.el index b6645a9297..f2b04769ef 100644 --- a/test/persist-tests.el +++ b/test/persist-tests.el @@ -25,51 +25,41 @@ (ert-deftest test-persist-save-only-persistant () :type 'error :exclude-subtypes t)) -(ert-deftest test-persist-save () - (with-local-temp-persist - (let ((sym (cl-gensym))) - ;; precondition - (should-not (file-exists-p (persist--file-location sym))) - (set sym 10) - (persist-symbol sym 10) - (persist-save sym) - (should t) - (should-not (file-exists-p (persist--file-location sym))) - (set sym 20) - (persist-save sym) - (should (file-exists-p (persist--file-location sym))) - (should - (string-match-p - "20" - (with-temp-buffer - (insert-file-contents (persist--file-location sym)) - (buffer-string)))) - (set sym 10) - (persist-save sym) - (should-not (file-exists-p (persist--file-location sym))) - (should-error - (persist-save 'fred))))) +(defmacro persist-test-persist-save (init default change printed-changed) + "Test persisting symbols. +- symbol is not persisted when value is set to INIT and default + value is set to DEFAULT. +- symbol is persisted when value is changed according to CHANGE. +- persisted file contents match PRINTED-CHANGED. +- symbol is not persisted after value is set back to DEFAULT." + `(with-local-temp-persist + (let ((sym (cl-gensym))) + (should-not (file-exists-p (persist--file-location sym))) + (set sym ,init) + (persist-symbol sym ,default) + (persist-save sym) + (should t) + (should-not (file-exists-p (persist--file-location sym))) + ,change + (persist-save sym) + (should (file-exists-p (persist--file-location sym))) + (should + (string-match-p + ,printed-changed + (with-temp-buffer + (insert-file-contents (persist--file-location sym)) + (buffer-string)))) + (set sym ,default) + (persist-save sym) + (should-not (file-exists-p (persist--file-location sym)))))) -(ert-deftest test-persist-save-non-number () - "Test saving something that is not a number. +(ert-deftest test-persist-save-number () + "Test saving number." + (persist-test-persist-save 1 1 (set sym 2) "2")) -`test-persist-save' missed " - (with-local-temp-persist - (let ((sym (cl-gensym))) - (set sym "fred") - (persist-symbol sym "fred") - (persist-save sym) - (should t) - (should-not (file-exists-p (persist--file-location sym))) - (set sym "george") - (persist-save sym) - (should (file-exists-p (persist--file-location sym))) - (should - (string-match-p - "george" - (with-temp-buffer - (insert-file-contents (persist--file-location sym)) - (buffer-string))))))) +(ert-deftest test-persist-save-string () + "Test saving string." + (persist-test-persist-save "foo" "foo" (set sym "bar") "bar")) (ert-deftest test-persist-load () (with-local-temp-persist -- 2.41.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: 0002-Add-persist-equal.patch --] [-- Type: text/x-diff, Size: 1394 bytes --] From b379d8d1779e0190541ef7f8adf39dfe4d4c551a Mon Sep 17 00:00:00 2001 From: Joseph Turner <joseph@breatheoutbreathe.in> Date: Sat, 2 Sep 2023 16:52:31 -0700 Subject: [PATCH 2/5] Add persist-equal * persist.el (persist-hash-equal): Like equal, but compares hash tables also. See bug#63671 for a discussion of built-in hash table comparison. --- persist.el | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/persist.el b/persist.el index d80943d19e..a707d038cd 100644 --- a/persist.el +++ b/persist.el @@ -187,5 +187,25 @@ (defun persist--save-all () (add-hook 'kill-emacs-hook 'persist--save-all) +(defun persist-equal (a b) + "Return non-nil when the values of A and B are equal. +A and B are compared using `equal' unless they are both hash +tables. In that case, the following are compared: + +- hash table count +- hash table predicate +- values, using `persist-equal'" + (if (and (hash-table-p a) (hash-table-p b)) + (and (= (hash-table-count a) (hash-table-count b)) + (eq (hash-table-test a) (hash-table-test b)) + (catch 'done + (maphash + (lambda (key a-value) + (unless (persist-equal a-value (gethash key b (not a-value))) + (throw 'done nil))) + a) + t)) + (equal a b))) + (provide 'persist) ;;; persist.el ends here -- 2.41.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #4: 0003-Make-persist-defvar-work-with-hash-tables.patch --] [-- Type: text/x-diff, Size: 2645 bytes --] From 11194569423dcdf8778a55f59dbca8f49e8b7b37 Mon Sep 17 00:00:00 2001 From: Joseph Turner <joseph@breatheoutbreathe.in> Date: Sun, 3 Sep 2023 17:10:38 -0700 Subject: [PATCH 3/5] Make persist-defvar work with hash tables Previously, when persist-defvar received a hash table for an initial value, updated values were not persisted. * persist.el (persist-symbol): Use hash table copy as default so that the original table can be modified without modifying the default value. (persist-save): Use persist-equal to ensure that hash tables are correctly compared * test/persist-tests.el (test-persist-save-hash): Test hash tables persistence. --- persist.el | 8 +++++--- test/persist-tests.el | 8 ++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/persist.el b/persist.el index a707d038cd..7b2ab491d7 100644 --- a/persist.el +++ b/persist.el @@ -118,7 +118,9 @@ (defun persist-symbol (symbol &optional initvalue) (let ((initvalue (or initvalue (symbol-value symbol)))) (add-to-list 'persist--symbols symbol) (put symbol 'persist t) - (put symbol 'persist-default initvalue))) + (if (hash-table-p initvalue) + (put symbol 'persist-default (copy-hash-table initvalue)) + (put symbol 'persist-default initvalue)))) (defun persist--persistant-p (symbol) "Return non-nil if SYMBOL is a persistant variable." @@ -133,8 +135,8 @@ (defun persist-save (symbol) (error (format "Symbol %s is not persistant" symbol))) (let ((symbol-file-loc (persist--file-location symbol))) - (if (equal (symbol-value symbol) - (persist-default symbol)) + (if (persist-equal (symbol-value symbol) + (persist-default symbol)) (when (file-exists-p symbol-file-loc) (delete-file symbol-file-loc)) (let ((dir-loc diff --git a/test/persist-tests.el b/test/persist-tests.el index f2b04769ef..90adf1c6d6 100644 --- a/test/persist-tests.el +++ b/test/persist-tests.el @@ -61,6 +61,14 @@ (ert-deftest test-persist-save-string () "Test saving string." (persist-test-persist-save "foo" "foo" (set sym "bar") "bar")) +(ert-deftest test-persist-save-hash () + "Test saving hash table." + (let* ((hash (make-hash-table)) + (default (copy-hash-table hash))) + (persist-test-persist-save hash default + (puthash 'foo "bar" (symbol-value sym)) + "#s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8125 data (foo \"bar\"))"))) + (ert-deftest test-persist-load () (with-local-temp-persist (let ((sym (cl-gensym))) -- 2.41.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #5: 0004-Add-persist-copy-tree.patch --] [-- Type: text/x-diff, Size: 1983 bytes --] From f360f7ae53125a847c2a8d5762ca5f08d16445b9 Mon Sep 17 00:00:00 2001 From: Joseph Turner <joseph@breatheoutbreathe.in> Date: Tue, 23 May 2023 13:43:02 -0700 Subject: [PATCH 4/5] Add persist-copy-tree The behavior of copy-tree was changed in Emacs 30. This function will ensure that persist works correctly for previous Emacs versions. * persist.el (persist-copy-tree): Add copy-tree, so that records can be compared. --- persist.el | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/persist.el b/persist.el index 7b2ab491d7..93444995f2 100644 --- a/persist.el +++ b/persist.el @@ -209,5 +209,33 @@ (defun persist-equal (a b) t)) (equal a b))) +(defun persist-copy-tree (tree &optional vectors-and-records) + "Make a copy of TREE. +If TREE is a cons cell, this recursively copies both its car and its cdr. +Contrast to `copy-sequence', which copies only along the cdrs. +With the second argument VECTORS-AND-RECORDS non-nil, this +traverses and copies vectors and records as well as conses." + (declare (side-effect-free error-free)) + (if (consp tree) + (let (result) + (while (consp tree) + (let ((newcar (car tree))) + (if (or (consp (car tree)) + (and vectors-and-records + (or (vectorp (car tree)) (recordp (car tree))))) + (setq newcar (persist-copy-tree (car tree) vectors-and-records))) + (push newcar result)) + (setq tree (cdr tree))) + (nconc (nreverse result) + (if (and vectors-and-records (or (vectorp tree) (recordp tree))) + (persist-copy-tree tree vectors-and-records) + tree))) + (if (and vectors-and-records (or (vectorp tree) (recordp tree))) + (let ((i (length (setq tree (copy-sequence tree))))) + (while (>= (setq i (1- i)) 0) + (aset tree i (persist-copy-tree (aref tree i) vectors-and-records))) + tree) + tree))) + (provide 'persist) ;;; persist.el ends here -- 2.41.0 [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #6: 0005-Make-persist-defvar-work-with-records.patch --] [-- Type: text/x-diff, Size: 2019 bytes --] From ea57e6205b10678b9c26f7dcf3704e2a7acb25a7 Mon Sep 17 00:00:00 2001 From: Joseph Turner <joseph@breatheoutbreathe.in> Date: Tue, 23 May 2023 13:44:40 -0700 Subject: [PATCH 5/5] Make persist-defvar work with records Previously, when persist-defvar received a record for an initial value, updated values were not persisted. * persist.el (persist-symbol): Set default to a copy of initvalue so when initvalue is a record, the original can be modified without modifying the default. * test/persist-tests.el: Test persist-save with a record. --- persist.el | 2 +- test/persist-tests.el | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/persist.el b/persist.el index 93444995f2..e43171459e 100644 --- a/persist.el +++ b/persist.el @@ -120,7 +120,7 @@ (defun persist-symbol (symbol &optional initvalue) (put symbol 'persist t) (if (hash-table-p initvalue) (put symbol 'persist-default (copy-hash-table initvalue)) - (put symbol 'persist-default initvalue)))) + (put symbol 'persist-default (persist-copy-tree initvalue t))))) (defun persist--persistant-p (symbol) "Return non-nil if SYMBOL is a persistant variable." diff --git a/test/persist-tests.el b/test/persist-tests.el index 90adf1c6d6..62d8501493 100644 --- a/test/persist-tests.el +++ b/test/persist-tests.el @@ -69,6 +69,14 @@ (ert-deftest test-persist-save-hash () (puthash 'foo "bar" (symbol-value sym)) "#s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8125 data (foo \"bar\"))"))) +(ert-deftest test-persist-save-record () + "Test saving record." + (let* ((rec (record 'foo 'a 'b)) + (default (copy-sequence rec))) + (persist-test-persist-save rec default + (setf (aref (symbol-value sym) 2) 'quux) + "#s(foo a quux)"))) + (ert-deftest test-persist-load () (with-local-temp-persist (let ((sym (cl-gensym))) -- 2.41.0 ^ permalink raw reply related [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-09-04 22:28 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-05 21:06 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-08 11:30 ` Ihor Radchenko 0 siblings, 1 reply; 44+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-05 21:06 UTC (permalink / raw) To: Joseph Turner; +Cc: Adam Porter, Eli Zaretskii, phillip.lord, 63513-done > Here you go! Thanks, pushed! Stefan ^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-09-05 21:06 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-08 11:30 ` Ihor Radchenko 2023-09-08 11:58 ` Eli Zaretskii 2023-09-08 16:36 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 2 replies; 44+ messages in thread From: Ihor Radchenko @ 2023-09-08 11:30 UTC (permalink / raw) To: Stefan Monnier Cc: Adam Porter, Eli Zaretskii, phillip.lord, 63513-done, Joseph Turner Stefan Monnier via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org> writes: >> Here you go! > > Thanks, pushed! May it be possible to promote `persist-hash-equal' and `persist-copy-tree' to common subr.el functions? The topic of comparing hash tables has been previously discussed in https://yhetil.org/emacs-devel/871qvz4kdw.fsf@localhost/ -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-09-08 11:30 ` Ihor Radchenko @ 2023-09-08 11:58 ` Eli Zaretskii 2023-09-08 12:06 ` Ihor Radchenko 2023-09-08 16:36 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 1 sibling, 1 reply; 44+ messages in thread From: Eli Zaretskii @ 2023-09-08 11:58 UTC (permalink / raw) To: Ihor Radchenko; +Cc: adam, phillip.lord, 63513-done, monnier, joseph > From: Ihor Radchenko <yantar92@posteo.net> > Cc: Joseph Turner <joseph@breatheoutbreathe.in>, Adam Porter > <adam@alphapapa.net>, Eli Zaretskii <eliz@gnu.org>, > phillip.lord@russet.org.uk, 63513-done@debbugs.gnu.org > Date: Fri, 08 Sep 2023 11:30:52 +0000 > > May it be possible to promote `persist-hash-equal' and > `persist-copy-tree' to common subr.el functions? Why do we need them in subr.el, i.e. preloaded? Why cannot these functions be autoloaded instead? ^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-09-08 11:58 ` Eli Zaretskii @ 2023-09-08 12:06 ` Ihor Radchenko 2023-09-08 12:46 ` Eli Zaretskii 0 siblings, 1 reply; 44+ messages in thread From: Ihor Radchenko @ 2023-09-08 12:06 UTC (permalink / raw) To: Eli Zaretskii; +Cc: adam, phillip.lord, 63513-done, monnier, joseph Eli Zaretskii <eliz@gnu.org> writes: >> May it be possible to promote `persist-hash-equal' and >> `persist-copy-tree' to common subr.el functions? > > Why do we need them in subr.el, i.e. preloaded? Why cannot these > functions be autoloaded instead? Similar functions - `string-equal-ignore-case' and `copy-tree' - are already in subr.el. I do not see why the new functions discussed here should be any different. -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-09-08 12:06 ` Ihor Radchenko @ 2023-09-08 12:46 ` Eli Zaretskii 2023-09-08 12:51 ` Ihor Radchenko 0 siblings, 1 reply; 44+ messages in thread From: Eli Zaretskii @ 2023-09-08 12:46 UTC (permalink / raw) To: Ihor Radchenko; +Cc: adam, phillip.lord, 63513-done, monnier, joseph > From: Ihor Radchenko <yantar92@posteo.net> > Cc: monnier@iro.umontreal.ca, joseph@breatheoutbreathe.in, > adam@alphapapa.net, phillip.lord@russet.org.uk, 63513-done@debbugs.gnu.org > Date: Fri, 08 Sep 2023 12:06:06 +0000 > > Eli Zaretskii <eliz@gnu.org> writes: > > >> May it be possible to promote `persist-hash-equal' and > >> `persist-copy-tree' to common subr.el functions? > > > > Why do we need them in subr.el, i.e. preloaded? Why cannot these > > functions be autoloaded instead? > > Similar functions - `string-equal-ignore-case' and `copy-tree' - are > already in subr.el. I do not see why the new functions discussed here > should be any different. We make the decision whether a function must be preloaded in a case by case basis, to avoid making the memory footprint of an Emacs session larger than it needs to be. So arguments "by similarity" are not useful in this case; you need to explain why you think these functions are needed right from the startup. Valid reasons include, among others: . function is used by the startup code or during dumping . function is used by all or many important configurations immediately after startup ^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-09-08 12:46 ` Eli Zaretskii @ 2023-09-08 12:51 ` Ihor Radchenko 0 siblings, 0 replies; 44+ messages in thread From: Ihor Radchenko @ 2023-09-08 12:51 UTC (permalink / raw) To: Eli Zaretskii; +Cc: adam, phillip.lord, 63513-done, monnier, joseph Eli Zaretskii <eliz@gnu.org> writes: >> > Why do we need them in subr.el, i.e. preloaded? Why cannot these >> > functions be autoloaded instead? >> >> Similar functions - `string-equal-ignore-case' and `copy-tree' - are >> already in subr.el. I do not see why the new functions discussed here >> should be any different. > > We make the decision whether a function must be preloaded in a case by > case basis, to avoid making the memory footprint of an Emacs session > larger than it needs to be. So arguments "by similarity" are not > useful in this case; you need to explain why you think these functions > are needed right from the startup. > ... Got it. Then, I do not insist on subr.el specifically. Autoloading is fine. -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-09-08 11:30 ` Ihor Radchenko 2023-09-08 11:58 ` Eli Zaretskii @ 2023-09-08 16:36 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-08 17:06 ` Ihor Radchenko 1 sibling, 1 reply; 44+ messages in thread From: Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-08 16:36 UTC (permalink / raw) To: Ihor Radchenko Cc: Adam Porter, Eli Zaretskii, phillip.lord, 63513-done, Joseph Turner >>> Here you go! >> Thanks, pushed! > May it be possible to promote `persist-hash-equal' and > `persist-copy-tree' to common subr.el functions? > The topic of comparing hash tables has been previously discussed in > https://yhetil.org/emacs-devel/871qvz4kdw.fsf@localhost/ Hmm... AFAICT `persist-copy-tree` is a copy of our current `copy-tree`, so there's nothing to do there :-) As for `persist-hash-equal` (which is actually called `persist-equal`, AFAICT), I think if we want to move it out of `persist.el` we need to improve it so it also looks inside hash-tables that occur within vectors, conses, etc... Maybe, like Sam Steingold suggested, we should simply consider the current treatment of `equal` on hash-tables to be a bug. Stefan ^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-09-08 16:36 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-08 17:06 ` Ihor Radchenko 2023-09-08 17:10 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 44+ messages in thread From: Ihor Radchenko @ 2023-09-08 17:06 UTC (permalink / raw) To: Stefan Monnier Cc: Adam Porter, Eli Zaretskii, phillip.lord, 63513-done, Joseph Turner Stefan Monnier <monnier@iro.umontreal.ca> writes: >>>> Here you go! >>> Thanks, pushed! >> May it be possible to promote `persist-hash-equal' and >> `persist-copy-tree' to common subr.el functions? >> The topic of comparing hash tables has been previously discussed in >> https://yhetil.org/emacs-devel/871qvz4kdw.fsf@localhost/ > > Hmm... AFAICT `persist-copy-tree` is a copy of our current `copy-tree`, > so there's nothing to do there :-) Err... Then, wouldn't it be better to contribute this function to compat.el and use it from there? > As for `persist-hash-equal` (which is actually called `persist-equal`, > AFAICT), I think if we want to move it out of `persist.el` we need to > improve it so it also looks inside hash-tables that occur within > vectors, conses, etc... > > Maybe, like Sam Steingold suggested, we should simply consider the > current treatment of `equal` on hash-tables to be a bug. That thread had no progress for quite a while. I thought that having `hash-equal' function could at least be an improvement (clearly, it is being used 🙂). But if you have an idea how to move the original discussion forward, please share it. AFAIU, no actionable conclusion have been reached in the linked thread. -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-09-08 17:06 ` Ihor Radchenko @ 2023-09-08 17:10 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-09 10:01 ` Ihor Radchenko 0 siblings, 1 reply; 44+ messages in thread From: Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-08 17:10 UTC (permalink / raw) To: Ihor Radchenko Cc: Adam Porter, Eli Zaretskii, 63513-done, Stefan Monnier, phillip.lord Ihor Radchenko <yantar92@posteo.net> writes: > Stefan Monnier <monnier@iro.umontreal.ca> writes: > >>>>> Here you go! >>>> Thanks, pushed! >>> May it be possible to promote `persist-hash-equal' and >>> `persist-copy-tree' to common subr.el functions? >>> The topic of comparing hash tables has been previously discussed in >>> https://yhetil.org/emacs-devel/871qvz4kdw.fsf@localhost/ >> >> Hmm... AFAICT `persist-copy-tree` is a copy of our current `copy-tree`, >> so there's nothing to do there :-) > > Err... > Then, wouldn't it be better to contribute this function to compat.el and > use it from there? The new behavior of copy-tree has already been added to compat.el: https://github.com/emacs-compat/compat/pull/25 However, that change currently only exists in compat's emacs-30 branch. I did not know if it was acceptable for persist.el to require compat when I wrote these patches. If we agree that it is acceptable, then I'm happy to submit a patch to replace (persist-copy-tree ...) with (compat-call copy-tree ...), but we'll have to wait to apply the patch until after the compat.el emacs-30 branch is merged into master. ^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-09-08 17:10 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-09 10:01 ` Ihor Radchenko 2023-09-09 10:15 ` Daniel Mendler 0 siblings, 1 reply; 44+ messages in thread From: Ihor Radchenko @ 2023-09-09 10:01 UTC (permalink / raw) To: Joseph Turner Cc: 63513-done, Daniel Mendler, Stefan Monnier, Adam Porter, Eli Zaretskii, phillip.lord Joseph Turner <joseph@breatheoutbreathe.in> writes: >> Then, wouldn't it be better to contribute this function to compat.el and >> use it from there? > > The new behavior of copy-tree has already been added to compat.el: > > https://github.com/emacs-compat/compat/pull/25 > > However, that change currently only exists in compat's emacs-30 branch. I see. > I did not know if it was acceptable for persist.el to require compat > when I wrote these patches. If we agree that it is acceptable, then I'm > happy to submit a patch to replace (persist-copy-tree ...) with > (compat-call copy-tree ...), but we'll have to wait to apply the patch > until after the compat.el emacs-30 branch is merged into master. AFAIU, the recommended way to implement compat function definitions that are not yet added to compat.el is using `compat-defun' + `compat-call'. Then, one can simply drop `compat-defun' after the function is finally release with compat.el without touching the rest of the code. CCing Daniel. -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-09-09 10:01 ` Ihor Radchenko @ 2023-09-09 10:15 ` Daniel Mendler 2023-09-09 11:35 ` Ihor Radchenko 0 siblings, 1 reply; 44+ messages in thread From: Daniel Mendler @ 2023-09-09 10:15 UTC (permalink / raw) To: Ihor Radchenko, Joseph Turner Cc: Adam Porter, Eli Zaretskii, 63513-done, Stefan Monnier, phillip.lord On 9/9/23 12:01, Ihor Radchenko wrote: > Joseph Turner <joseph@breatheoutbreathe.in> writes: > >>> Then, wouldn't it be better to contribute this function to compat.el and >>> use it from there? >> >> The new behavior of copy-tree has already been added to compat.el: >> >> https://github.com/emacs-compat/compat/pull/25 >> >> However, that change currently only exists in compat's emacs-30 branch. > > I see. > >> I did not know if it was acceptable for persist.el to require compat >> when I wrote these patches. If we agree that it is acceptable, then I'm >> happy to submit a patch to replace (persist-copy-tree ...) with >> (compat-call copy-tree ...), but we'll have to wait to apply the patch >> until after the compat.el emacs-30 branch is merged into master. > > AFAIU, the recommended way to implement compat function definitions that > are not yet added to compat.el is using `compat-defun' + `compat-call'. > Then, one can simply drop `compat-defun' after the function is finally > release with compat.el without touching the rest of the code. `compat-call` is meant to be used to call "extended functions", for example functions with additional arguments. See the Compat manual for details. The macros from compat-macs.el (`compat-defun` etc.) are internal as documented in the file compat-macs.el. These macros must not be used outside Compat. So using Compat here has to wait until compat-30.x is released. Daniel ^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-09-09 10:15 ` Daniel Mendler @ 2023-09-09 11:35 ` Ihor Radchenko 2023-09-09 11:57 ` Daniel Mendler 0 siblings, 1 reply; 44+ messages in thread From: Ihor Radchenko @ 2023-09-09 11:35 UTC (permalink / raw) To: Daniel Mendler Cc: 63513-done, Joseph Turner, Stefan Monnier, Adam Porter, Eli Zaretskii, phillip.lord Daniel Mendler <mail@daniel-mendler.de> writes: >> AFAIU, the recommended way to implement compat function definitions that >> are not yet added to compat.el is using `compat-defun' + `compat-call'. >> Then, one can simply drop `compat-defun' after the function is finally >> release with compat.el without touching the rest of the code. > > `compat-call` is meant to be used to call "extended functions", for > example functions with additional arguments. See the Compat manual for > details. > > The macros from compat-macs.el (`compat-defun` etc.) are internal as > documented in the file compat-macs.el. These macros must not be used > outside Compat. > > So using Compat here has to wait until compat-30.x is released. And do I understand correctly that compat-30 will only be released after Emacs 30 is released? If so, it is awkward for :core packages. -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-09-09 11:35 ` Ihor Radchenko @ 2023-09-09 11:57 ` Daniel Mendler 2023-09-09 12:12 ` compat.el and Emacs unstable master branch features (was: bug#63513: [PATCH] Make persist-defvar work with records and hash tables) Ihor Radchenko 0 siblings, 1 reply; 44+ messages in thread From: Daniel Mendler @ 2023-09-09 11:57 UTC (permalink / raw) To: Ihor Radchenko Cc: 63513-done, Joseph Turner, Stefan Monnier, Adam Porter, Eli Zaretskii, phillip.lord On 9/9/23 13:35, Ihor Radchenko wrote: >> So using Compat here has to wait until compat-30.x is released. > > And do I understand correctly that compat-30 will only be released after > Emacs 30 is released? If so, it is awkward for :core packages. compat-30 can be released as soon as Emacs 30 has been reasonably stabilized, e.g., when the emacs-30 branch has been frozen, or a bit before that. We cannot release much earlier since APIs may still change and it is probably undesired to release unfinished APIs to the public too early. For reference, I've created the compat-29.1.1 release around the day that Eli announced the emacs-29 branch freeze. Daniel ^ permalink raw reply [flat|nested] 44+ messages in thread
* compat.el and Emacs unstable master branch features (was: bug#63513: [PATCH] Make persist-defvar work with records and hash tables) 2023-09-09 11:57 ` Daniel Mendler @ 2023-09-09 12:12 ` Ihor Radchenko 2023-09-09 12:29 ` Daniel Mendler 0 siblings, 1 reply; 44+ messages in thread From: Ihor Radchenko @ 2023-09-09 12:12 UTC (permalink / raw) To: Daniel Mendler Cc: Joseph Turner, Stefan Monnier, Adam Porter, Eli Zaretskii, phillip.lord, emacs-devel, ~pkal/compat-devel Daniel Mendler <mail@daniel-mendler.de> writes: > On 9/9/23 13:35, Ihor Radchenko wrote: >>> So using Compat here has to wait until compat-30.x is released. >> >> And do I understand correctly that compat-30 will only be released after >> Emacs 30 is released? If so, it is awkward for :core packages. > > compat-30 can be released as soon as Emacs 30 has been reasonably > stabilized, e.g., when the emacs-30 branch has been frozen, or a bit > before that. We cannot release much earlier since APIs may still change > and it is probably undesired to release unfinished APIs to the public > too early. For reference, I've created the compat-29.1.1 release around > the day that Eli announced the emacs-29 branch freeze. I understand the logic, but it does not make things less awkward. Sometimes, Emacs core packages that are also distributed on ELPA rely on bugfixes (changed functions) or new functions from master. It is indeed viable to copy-paste the needed functions into the package code, but it _feels_ like something compat.el may provide support for. May it be possible to provide a public API in compat.el to define compat function versions before they appear in compat.el properly? -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: compat.el and Emacs unstable master branch features (was: bug#63513: [PATCH] Make persist-defvar work with records and hash tables) 2023-09-09 12:12 ` compat.el and Emacs unstable master branch features (was: bug#63513: [PATCH] Make persist-defvar work with records and hash tables) Ihor Radchenko @ 2023-09-09 12:29 ` Daniel Mendler 2023-09-09 16:52 ` Joseph Turner 2023-09-11 8:45 ` Ihor Radchenko 0 siblings, 2 replies; 44+ messages in thread From: Daniel Mendler @ 2023-09-09 12:29 UTC (permalink / raw) To: Ihor Radchenko Cc: Joseph Turner, Stefan Monnier, Adam Porter, Eli Zaretskii, phillip.lord, emacs-devel, ~pkal/compat-devel On 9/9/23 14:12, Ihor Radchenko wrote: > Daniel Mendler <mail@daniel-mendler.de> writes: >> compat-30 can be released as soon as Emacs 30 has been reasonably >> stabilized, e.g., when the emacs-30 branch has been frozen, or a bit >> before that. We cannot release much earlier since APIs may still change >> and it is probably undesired to release unfinished APIs to the public >> too early. For reference, I've created the compat-29.1.1 release around >> the day that Eli announced the emacs-29 branch freeze. > > It is indeed viable to copy-paste the needed functions into the package > code, but it _feels_ like something compat.el may provide support for. > > May it be possible to provide a public API in compat.el to define > compat function versions before they appear in compat.el properly? I see your point, but I think that Compat provides value for both external and core packages given its current conservative approach. All that is needed is to wait for a while after some API has been added and Compat has been synchronized. Note that we haven't seen many API additions in Emacs 30 so far. Compare this to compat-29.el which provides a rich set of new APIs which are all available for external and core packages depending on older Emacs versions. I suggest to copy new functions temporarily to the package in question with an fboundp check, with an additional TODO comment. We can synchronize with Compat afterwards. Providing a public API won't work since Compat is not included in Emacs itself. A design criterion of Compat is also to keep the public API surface as small as possible. Daniel ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: compat.el and Emacs unstable master branch features (was: bug#63513: [PATCH] Make persist-defvar work with records and hash tables) 2023-09-09 12:29 ` Daniel Mendler @ 2023-09-09 16:52 ` Joseph Turner 2023-09-11 8:45 ` Ihor Radchenko 1 sibling, 0 replies; 44+ messages in thread From: Joseph Turner @ 2023-09-09 16:52 UTC (permalink / raw) To: Daniel Mendler Cc: Ihor Radchenko, Stefan Monnier, Adam Porter, Eli Zaretskii, phillip.lord, emacs-devel, ~pkal/compat-devel Daniel Mendler <mail@daniel-mendler.de> writes: > I suggest to copy new functions temporarily to the package in question > with an fboundp check, with an additional TODO comment. We can > synchronize with Compat afterwards. Providing a public API won't work > since Compat is not included in Emacs itself. A design criterion of > Compat is also to keep the public API surface as small as possible. fboundp won't work here because copy-tree is available in earlier versions of Emacs. Since its behavior changed in 30, we could do a version check + TODO comment? ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: compat.el and Emacs unstable master branch features (was: bug#63513: [PATCH] Make persist-defvar work with records and hash tables) 2023-09-09 12:29 ` Daniel Mendler 2023-09-09 16:52 ` Joseph Turner @ 2023-09-11 8:45 ` Ihor Radchenko 2023-09-12 10:02 ` compat.el and Emacs unstable master branch features Philip Kaludercic 1 sibling, 1 reply; 44+ messages in thread From: Ihor Radchenko @ 2023-09-11 8:45 UTC (permalink / raw) To: Daniel Mendler Cc: Joseph Turner, Stefan Monnier, Adam Porter, Eli Zaretskii, phillip.lord, emacs-devel, ~pkal/compat-devel Daniel Mendler <mail@daniel-mendler.de> writes: > ... Providing a public API won't work > since Compat is not included in Emacs itself. A design criterion of > Compat is also to keep the public API surface as small as possible. Maybe it is the time to consider including the compat.el API into Emacs? We are getting a number of :core packages published on ELPA and naturally having to solve various compatibility problems. -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: compat.el and Emacs unstable master branch features 2023-09-11 8:45 ` Ihor Radchenko @ 2023-09-12 10:02 ` Philip Kaludercic 2023-09-12 10:27 ` Daniel Mendler 0 siblings, 1 reply; 44+ messages in thread From: Philip Kaludercic @ 2023-09-12 10:02 UTC (permalink / raw) To: Ihor Radchenko Cc: Daniel Mendler, Joseph Turner, Stefan Monnier, Adam Porter, Eli Zaretskii, phillip.lord, emacs-devel, ~pkal/compat-devel Ihor Radchenko <yantar92@posteo.net> writes: > Daniel Mendler <mail@daniel-mendler.de> writes: > >> ... Providing a public API won't work >> since Compat is not included in Emacs itself. A design criterion of >> Compat is also to keep the public API surface as small as possible. > > Maybe it is the time to consider including the compat.el API into Emacs? > We are getting a number of :core packages published on ELPA and > naturally having to solve various compatibility problems. I am a bit behind wrt Compat development. Are we talking about adding the `compat-call, etc. macros to the core? So basically just a (defmacro compat-call (&rest args) args) that would be overriden by compat's compat-call, as soon as that is loaded ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: compat.el and Emacs unstable master branch features 2023-09-12 10:02 ` compat.el and Emacs unstable master branch features Philip Kaludercic @ 2023-09-12 10:27 ` Daniel Mendler 2023-09-13 10:31 ` Philip Kaludercic 0 siblings, 1 reply; 44+ messages in thread From: Daniel Mendler @ 2023-09-12 10:27 UTC (permalink / raw) To: Philip Kaludercic, Ihor Radchenko Cc: Joseph Turner, Stefan Monnier, Adam Porter, Eli Zaretskii, phillip.lord, emacs-devel, ~pkal/compat-devel On 9/12/23 12:02, Philip Kaludercic wrote: > Ihor Radchenko <yantar92@posteo.net> writes: > >> Daniel Mendler <mail@daniel-mendler.de> writes: >> >>> ... Providing a public API won't work >>> since Compat is not included in Emacs itself. A design criterion of >>> Compat is also to keep the public API surface as small as possible. >> >> Maybe it is the time to consider including the compat.el API into Emacs? >> We are getting a number of :core packages published on ELPA and >> naturally having to solve various compatibility problems. > > I am a bit behind wrt Compat development. Are we talking about adding > the `compat-call, etc. macros to the core? So basically just a > > (defmacro compat-call (&rest args) args) > > that would be overriden by compat's compat-call, as soon as that is > loaded Yes, if the Emacs maintainers agree I think this could be done. Take compat.el, remove the part which requires compat-29, and copy it to lisp/ or lisp/emacs-lisp/. As you said, if Compat (the package) is installed it will be preferred over the core compat.el. The advantage of this move is that core package could require compat directly without passing a noerror argument to require. Furthermore `compat-call' and `compat-function' would be available and wouldn't have to be copied as is currently the case for example in erc-compat.el. Daniel ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: compat.el and Emacs unstable master branch features 2023-09-12 10:27 ` Daniel Mendler @ 2023-09-13 10:31 ` Philip Kaludercic 2023-09-13 17:11 ` Daniel Mendler 0 siblings, 1 reply; 44+ messages in thread From: Philip Kaludercic @ 2023-09-13 10:31 UTC (permalink / raw) To: Daniel Mendler Cc: Ihor Radchenko, Joseph Turner, Stefan Monnier, Adam Porter, Eli Zaretskii, phillip.lord, emacs-devel, ~pkal/compat-devel [-- Attachment #1: Type: text/plain, Size: 1484 bytes --] Daniel Mendler <mail@daniel-mendler.de> writes: > On 9/12/23 12:02, Philip Kaludercic wrote: >> Ihor Radchenko <yantar92@posteo.net> writes: >> >>> Daniel Mendler <mail@daniel-mendler.de> writes: >>> >>>> ... Providing a public API won't work >>>> since Compat is not included in Emacs itself. A design criterion of >>>> Compat is also to keep the public API surface as small as possible. >>> >>> Maybe it is the time to consider including the compat.el API into Emacs? >>> We are getting a number of :core packages published on ELPA and >>> naturally having to solve various compatibility problems. >> >> I am a bit behind wrt Compat development. Are we talking about adding >> the `compat-call, etc. macros to the core? So basically just a >> >> (defmacro compat-call (&rest args) args) >> >> that would be overriden by compat's compat-call, as soon as that is >> loaded > > Yes, if the Emacs maintainers agree I think this could be done. Take > compat.el, remove the part which requires compat-29, and copy it to > lisp/ or lisp/emacs-lisp/. As you said, if Compat (the package) is > installed it will be preferred over the core compat.el. The advantage of > this move is that core package could require compat directly without > passing a noerror argument to require. Furthermore `compat-call' and > `compat-function' would be available and wouldn't have to be copied as > is currently the case for example in erc-compat.el. That sounds good! How does this look like: [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Add-the-public-API-of-Compat-to-the-core.patch --] [-- Type: text/x-diff, Size: 3834 bytes --] From 3245c3c4e6a8a4c35c4072df3a0bfefcabe0555d Mon Sep 17 00:00:00 2001 From: Philip Kaludercic <philipk@posteo.net> Date: Wed, 13 Sep 2023 12:26:22 +0200 Subject: [PATCH] Add the public API of Compat to the core * lisp/emacs-lisp/compat.el: Add stub file with minimal definitions, so that core packages, that haven't been installed from ELPA, can make use of the public API and use more recent function signatures. * lisp/progmodes/python.el (compat): Remove 'noerror flag, because Compat can now be required without the real package being available. --- lisp/emacs-lisp/compat.el | 61 +++++++++++++++++++++++++++++++++++++++ lisp/progmodes/python.el | 2 +- 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 lisp/emacs-lisp/compat.el diff --git a/lisp/emacs-lisp/compat.el b/lisp/emacs-lisp/compat.el new file mode 100644 index 00000000000..4c60093b6be --- /dev/null +++ b/lisp/emacs-lisp/compat.el @@ -0,0 +1,61 @@ +;;; compat.el --- Pseudo-Compatibility for Elisp -*- lexical-binding: t; -*- + +;; Copyright (C) 2021-2023 Free Software Foundation, Inc. + +;; Author: \ +;; Philip Kaludercic <philipk@posteo.net>, \ +;; Daniel Mendler <mail@daniel-mendler.de> +;; Maintainer: \ +;; Daniel Mendler <mail@daniel-mendler.de>, \ +;; Compat Development <~pkal/compat-devel@lists.sr.ht>, +;; emacs-devel@gnu.org +;; URL: https://github.com/emacs-compat/compat +;; Version: 1.0 +;; Keywords: lisp, maint + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; The Compat package on ELPA provides forward-compatibility +;; definitions for other packages. While mostly transparent, a +;; minimal API is necessary whenever core definitions change calling +;; conventions (e.g. `plist-get' can be invoked with a predicate from +;; Emacs 29.1 onward). For core packages on ELPA to be able to take +;; advantage of this functionality, the macros `compat-function' and +;; `compat-call' have to be available in the core, usable even if +;; users do not have the Compat package installed, which this file +;; ensures. + +;; Note that Compat is not a core package and this file is not +;; available on GNU ELPA. + +;;; Code: + +(defmacro compat-function (fun) + "Return compatibility function symbol for FUN. +This is a pseudo-compatibility stub for core packages on ELPA, +that depend on the Compat package, whenever the user doesn't have +the package installed on their current system." + `#',fun) + +(defmacro compat-call (fun &rest args) + "Call compatibility function or macro FUN with ARGS. +This is a pseudo-compatibility stub for core packages on ELPA, +that depend on the Compat package, whenever the user doesn't have +the package installed on their current system." + (cons fun args)) + +(provide 'compat) +;;; compat.el ends here diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 4b940b3f13b..bf0e27bc786 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -264,7 +264,7 @@ (eval-when-compile (require 'subr-x)) ;For `string-empty-p' and `string-join'. (require 'treesit) (require 'pcase) -(require 'compat nil 'noerror) +(require 'compat) (require 'project nil 'noerror) (require 'seq) -- 2.39.2 ^ permalink raw reply related [flat|nested] 44+ messages in thread
* Re: compat.el and Emacs unstable master branch features 2023-09-13 10:31 ` Philip Kaludercic @ 2023-09-13 17:11 ` Daniel Mendler 2023-10-15 8:43 ` Ihor Radchenko 0 siblings, 1 reply; 44+ messages in thread From: Daniel Mendler @ 2023-09-13 17:11 UTC (permalink / raw) To: Philip Kaludercic Cc: Ihor Radchenko, Joseph Turner, Stefan Monnier, Adam Porter, Eli Zaretskii, phillip.lord, emacs-devel, ~pkal/compat-devel On 9/13/23 12:31, Philip Kaludercic wrote: > Daniel Mendler <mail@daniel-mendler.de> writes: > >> On 9/12/23 12:02, Philip Kaludercic wrote: >>> Ihor Radchenko <yantar92@posteo.net> writes: >>> >>>> Daniel Mendler <mail@daniel-mendler.de> writes: >>>> >>>>> ... Providing a public API won't work >>>>> since Compat is not included in Emacs itself. A design criterion of >>>>> Compat is also to keep the public API surface as small as possible. >>>> >>>> Maybe it is the time to consider including the compat.el API into Emacs? >>>> We are getting a number of :core packages published on ELPA and >>>> naturally having to solve various compatibility problems. >>> >>> I am a bit behind wrt Compat development. Are we talking about adding >>> the `compat-call, etc. macros to the core? So basically just a >>> >>> (defmacro compat-call (&rest args) args) >>> >>> that would be overriden by compat's compat-call, as soon as that is >>> loaded >> >> Yes, if the Emacs maintainers agree I think this could be done. Take >> compat.el, remove the part which requires compat-29, and copy it to >> lisp/ or lisp/emacs-lisp/. As you said, if Compat (the package) is >> installed it will be preferred over the core compat.el. The advantage of >> this move is that core package could require compat directly without >> passing a noerror argument to require. Furthermore `compat-call' and >> `compat-function' would be available and wouldn't have to be copied as >> is currently the case for example in erc-compat.el. > > That sounds good! How does this look like: Yes, this is what I meant. I forgot to mention one additional advantage in my last mail: If the compat.el in core is registered with package.el as builtin with version 30, the ELPA Compat package wouldn't get pulled in by external packages which depend on Compat version 29. The core compat.el version should then be bumped together with the Emacs version. Daniel ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: compat.el and Emacs unstable master branch features 2023-09-13 17:11 ` Daniel Mendler @ 2023-10-15 8:43 ` Ihor Radchenko 2023-10-15 12:09 ` Philip Kaludercic 0 siblings, 1 reply; 44+ messages in thread From: Ihor Radchenko @ 2023-10-15 8:43 UTC (permalink / raw) To: Daniel Mendler Cc: Philip Kaludercic, Joseph Turner, Stefan Monnier, Adam Porter, Eli Zaretskii, phillip.lord, emacs-devel, ~pkal/compat-devel Daniel Mendler <mail@daniel-mendler.de> writes: >>> Yes, if the Emacs maintainers agree I think this could be done. Take >>> compat.el, remove the part which requires compat-29, and copy it to >>> lisp/ or lisp/emacs-lisp/. As you said, if Compat (the package) is >>> installed it will be preferred over the core compat.el. The advantage of >>> this move is that core package could require compat directly without >>> passing a noerror argument to require. Furthermore `compat-call' and >>> `compat-function' would be available and wouldn't have to be copied as >>> is currently the case for example in erc-compat.el. >> >> That sounds good! How does this look like: > > Yes, this is what I meant. I forgot to mention one additional advantage > in my last mail: If the compat.el in core is registered with package.el > as builtin with version 30, the ELPA Compat package wouldn't get pulled > in by external packages which depend on Compat version 29. The core > compat.el version should then be bumped together with the Emacs version. Nobody raised objections. I recommend sending the patch to debbugs (M-x submit-emacs-patch), so that it can be seen by Emacs maintainers. -- Ihor Radchenko // yantar92, Org mode contributor, Learn more about Org mode at <https://orgmode.org/>. Support Org development at <https://liberapay.com/org-mode>, or support my work at <https://liberapay.com/yantar92> ^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: compat.el and Emacs unstable master branch features 2023-10-15 8:43 ` Ihor Radchenko @ 2023-10-15 12:09 ` Philip Kaludercic 0 siblings, 0 replies; 44+ messages in thread From: Philip Kaludercic @ 2023-10-15 12:09 UTC (permalink / raw) To: Ihor Radchenko Cc: Daniel Mendler, Joseph Turner, Stefan Monnier, Adam Porter, Eli Zaretskii, phillip.lord, emacs-devel, ~pkal/compat-devel Ihor Radchenko <yantar92@posteo.net> writes: > Daniel Mendler <mail@daniel-mendler.de> writes: > >>>> Yes, if the Emacs maintainers agree I think this could be done. Take >>>> compat.el, remove the part which requires compat-29, and copy it to >>>> lisp/ or lisp/emacs-lisp/. As you said, if Compat (the package) is >>>> installed it will be preferred over the core compat.el. The advantage of >>>> this move is that core package could require compat directly without >>>> passing a noerror argument to require. Furthermore `compat-call' and >>>> `compat-function' would be available and wouldn't have to be copied as >>>> is currently the case for example in erc-compat.el. >>> >>> That sounds good! How does this look like: >> >> Yes, this is what I meant. I forgot to mention one additional advantage >> in my last mail: If the compat.el in core is registered with package.el >> as builtin with version 30, the ELPA Compat package wouldn't get pulled >> in by external packages which depend on Compat version 29. The core >> compat.el version should then be bumped together with the Emacs version. > > Nobody raised objections. I recommend sending the patch to debbugs (M-x > submit-emacs-patch), so that it can be seen by Emacs maintainers. See bug#66554. -- Philip Kaludercic ^ permalink raw reply [flat|nested] 44+ messages in thread
* bug#63513: [PATCH] Make persist-defvar work with records and hash tables 2023-09-04 17:05 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-04 22:28 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-05 15:08 ` phillip.lord 1 sibling, 0 replies; 44+ messages in thread From: phillip.lord @ 2023-09-05 15:08 UTC (permalink / raw) To: Stefan Monnier; +Cc: adam.porter, Eli Zaretskii, 63513, Joseph Turner On 2023-09-04 18:05, Stefan Monnier wrote: > Joseph Turner [2023-09-04 08:57:13] wrote: >> On September 4, 2023 4:33:55 AM PDT, Eli Zaretskii <eliz@gnu.org> >> wrote: >>>> From: Joseph Turner <joseph@breatheoutbreathe.in> >>>> Cc: phillip.lord@russet.org.uk, monnier@iro.umontreal.ca, >>>> 63513@debbugs.gnu.org, Adam Porter <adam.porter@47ap.net> >>>> Date: Sun, 03 Sep 2023 17:29:22 -0700 >>>> >>>> > Also, I think the new features warrant a NEWS entry. >>>> >>>> Should that go in the NEWS file in the main Emacs repo? I don't see >>>> a >>>> NEWS file in either of the main or externals/persist ELPA branches. >>> >>> I'm terribly sorry: I haven't realized this is for ELPA, I thought it >>> was for emacs.git. My bad Please ignore what I wrote in my previous >>> message. >> >> No problem! It gave me a chance to do a final editing pass. What's the >> next >> step? I would be glad for Phillip's review, if possible. > > I was about to ping Phil over on https://gitlab.com/phillord/persist/ > but was reminded along the way that Phil gave me write access to > that repository. > > Could you send me the result of your final editing pass? Indeed! I am afraid I am fairly unresponsive these days ("real life" intrudes), but I am more than happy for you to update there. Phil ^ permalink raw reply [flat|nested] 44+ messages in thread
end of thread, other threads:[~2023-10-15 12:09 UTC | newest] Thread overview: 44+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2022-06-08 8:41 Comparing hash table objects Ihor Radchenko 2022-06-08 8:51 ` Andreas Schwab 2022-06-08 9:17 ` Ihor Radchenko 2022-06-10 22:45 ` Richard Stallman 2022-06-11 5:52 ` Ihor Radchenko 2022-06-11 16:04 ` Stefan Monnier 2022-06-12 9:16 ` Ihor Radchenko 2022-06-12 23:55 ` Sam Steingold 2022-06-13 13:02 ` Stefan Monnier 2022-06-13 16:18 ` Sam Steingold 2023-05-15 5:56 ` bug#63513: [PATCH] Make persist-defvar work with records and hash tables Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-05-15 11:31 ` Eli Zaretskii 2023-05-23 20:14 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-02 23:54 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-03 6:08 ` Eli Zaretskii 2023-09-04 0:29 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-04 11:33 ` Eli Zaretskii 2023-09-04 15:57 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-04 17:05 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-04 22:28 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-05 21:06 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-08 11:30 ` Ihor Radchenko 2023-09-08 11:58 ` Eli Zaretskii 2023-09-08 12:06 ` Ihor Radchenko 2023-09-08 12:46 ` Eli Zaretskii 2023-09-08 12:51 ` Ihor Radchenko 2023-09-08 16:36 ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-08 17:06 ` Ihor Radchenko 2023-09-08 17:10 ` Joseph Turner via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-09 10:01 ` Ihor Radchenko 2023-09-09 10:15 ` Daniel Mendler 2023-09-09 11:35 ` Ihor Radchenko 2023-09-09 11:57 ` Daniel Mendler 2023-09-09 12:12 ` compat.el and Emacs unstable master branch features (was: bug#63513: [PATCH] Make persist-defvar work with records and hash tables) Ihor Radchenko 2023-09-09 12:29 ` Daniel Mendler 2023-09-09 16:52 ` Joseph Turner 2023-09-11 8:45 ` Ihor Radchenko 2023-09-12 10:02 ` compat.el and Emacs unstable master branch features Philip Kaludercic 2023-09-12 10:27 ` Daniel Mendler 2023-09-13 10:31 ` Philip Kaludercic 2023-09-13 17:11 ` Daniel Mendler 2023-10-15 8:43 ` Ihor Radchenko 2023-10-15 12:09 ` Philip Kaludercic 2023-09-05 15:08 ` bug#63513: [PATCH] Make persist-defvar work with records and hash tables phillip.lord
Code repositories for project(s) associated with this external index https://git.savannah.gnu.org/cgit/emacs.git https://git.savannah.gnu.org/cgit/emacs/org-mode.git This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.