diff options
| author | Stefan Monnier | 2021-12-04 13:47:19 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2021-12-04 13:47:35 -0500 |
| commit | de727b5886fb4a81df2dc17d9d094e915c1e9fb4 (patch) | |
| tree | c7e1f3ae109eb8cc6c11abf9391b25bf8d15b8cf | |
| parent | 63be97fb050545cc33ae5d857188ad45fbe27715 (diff) | |
| download | emacs-de727b5886fb4a81df2dc17d9d094e915c1e9fb4.tar.gz emacs-de727b5886fb4a81df2dc17d9d094e915c1e9fb4.zip | |
eieio-core.el: Allow assignment to cl-structs through `slot-value`
* lisp/emacs-lisp/eieio-core.el (eieio--validate-slot-value):
Obey the `:read-only` property of the slot.
(eieio-oset): Allow use on cl-structs as well.
(eieio-read-only): New error.
* test/lisp/emacs-lisp/eieio-tests/eieio-tests.el (eieio-test--struct):
Make the last field read-only.
(eieio-test-defstruct-slot-value): Test that cl-struct slots can be
assigned via `slot-value`.
| -rw-r--r-- | doc/misc/eieio.texi | 3 | ||||
| -rw-r--r-- | etc/NEWS | 2 | ||||
| -rw-r--r-- | lisp/emacs-lisp/eieio-core.el | 19 | ||||
| -rw-r--r-- | test/lisp/emacs-lisp/eieio-tests/eieio-tests.el | 7 |
4 files changed, 19 insertions, 12 deletions
diff --git a/doc/misc/eieio.texi b/doc/misc/eieio.texi index 2b0b1f7fd67..8a4b914687c 100644 --- a/doc/misc/eieio.texi +++ b/doc/misc/eieio.texi | |||
| @@ -703,8 +703,7 @@ This function retrieves the value of @var{slot} from @var{object}. | |||
| 703 | It can also be used on objects defined by @code{cl-defstruct}. | 703 | It can also be used on objects defined by @code{cl-defstruct}. |
| 704 | 704 | ||
| 705 | This is a generalized variable that can be used with @code{setf} to | 705 | This is a generalized variable that can be used with @code{setf} to |
| 706 | modify the value stored in @var{slot}, tho not for objects defined by | 706 | modify the value stored in @var{slot}. |
| 707 | @code{cl-defstruct}. | ||
| 708 | @xref{Generalized Variables,,,elisp,GNU Emacs Lisp Reference Manual}. | 707 | @xref{Generalized Variables,,,elisp,GNU Emacs Lisp Reference Manual}. |
| 709 | @end defun | 708 | @end defun |
| 710 | 709 | ||
| @@ -423,7 +423,7 @@ representation as emojis. | |||
| 423 | ** EIEIO | 423 | ** EIEIO |
| 424 | 424 | ||
| 425 | +++ | 425 | +++ |
| 426 | *** 'slot-value' can now be used to read slots of 'cl-defstruct' objects. | 426 | *** 'slot-value' can now be used to access slots of 'cl-defstruct' objects. |
| 427 | 427 | ||
| 428 | ** align | 428 | ** align |
| 429 | 429 | ||
diff --git a/lisp/emacs-lisp/eieio-core.el b/lisp/emacs-lisp/eieio-core.el index 7c5babcf54c..ca47ec77f76 100644 --- a/lisp/emacs-lisp/eieio-core.el +++ b/lisp/emacs-lisp/eieio-core.el | |||
| @@ -450,7 +450,7 @@ See `defclass' for more information." | |||
| 450 | )) | 450 | )) |
| 451 | 451 | ||
| 452 | ;; Now that everything has been loaded up, all our lists are backwards! | 452 | ;; Now that everything has been loaded up, all our lists are backwards! |
| 453 | ;; Fix that up now and then them into vectors. | 453 | ;; Fix that up now and turn them into vectors. |
| 454 | (cl-callf (lambda (slots) (apply #'vector (nreverse slots))) | 454 | (cl-callf (lambda (slots) (apply #'vector (nreverse slots))) |
| 455 | (eieio--class-slots newc)) | 455 | (eieio--class-slots newc)) |
| 456 | (cl-callf nreverse (eieio--class-initarg-tuples newc)) | 456 | (cl-callf nreverse (eieio--class-initarg-tuples newc)) |
| @@ -704,11 +704,15 @@ an error." | |||
| 704 | nil | 704 | nil |
| 705 | ;; Trim off object IDX junk added in for the object index. | 705 | ;; Trim off object IDX junk added in for the object index. |
| 706 | (setq slot-idx (- slot-idx (eval-when-compile eieio--object-num-slots))) | 706 | (setq slot-idx (- slot-idx (eval-when-compile eieio--object-num-slots))) |
| 707 | (let ((st (cl--slot-descriptor-type (aref (eieio--class-slots class) | 707 | (let* ((sd (aref (eieio--class-slots class) |
| 708 | slot-idx)))) | 708 | slot-idx)) |
| 709 | (if (not (eieio--perform-slot-validation st value)) | 709 | (st (cl--slot-descriptor-type sd))) |
| 710 | (signal 'invalid-slot-type | 710 | (cond |
| 711 | (list (eieio--class-name class) slot st value)))))) | 711 | ((not (eieio--perform-slot-validation st value)) |
| 712 | (signal 'invalid-slot-type | ||
| 713 | (list (eieio--class-name class) slot st value))) | ||
| 714 | ((alist-get :read-only (cl--slot-descriptor-props sd)) | ||
| 715 | (signal 'eieio-read-only (list (eieio--class-name class) slot))))))) | ||
| 712 | 716 | ||
| 713 | (defun eieio--validate-class-slot-value (class slot-idx value slot) | 717 | (defun eieio--validate-class-slot-value (class slot-idx value slot) |
| 714 | "Make sure that for CLASS referencing SLOT-IDX, VALUE is valid. | 718 | "Make sure that for CLASS referencing SLOT-IDX, VALUE is valid. |
| @@ -813,7 +817,7 @@ Fills in CLASS's SLOT with its default value." | |||
| 813 | (defun eieio-oset (obj slot value) | 817 | (defun eieio-oset (obj slot value) |
| 814 | "Do the work for the macro `oset'. | 818 | "Do the work for the macro `oset'. |
| 815 | Fills in OBJ's SLOT with VALUE." | 819 | Fills in OBJ's SLOT with VALUE." |
| 816 | (cl-check-type obj eieio-object) | 820 | (cl-check-type obj (or eieio-object cl-structure-object)) |
| 817 | (cl-check-type slot symbol) | 821 | (cl-check-type slot symbol) |
| 818 | (let* ((class (eieio--object-class obj)) | 822 | (let* ((class (eieio--object-class obj)) |
| 819 | (c (eieio--slot-name-index class slot))) | 823 | (c (eieio--slot-name-index class slot))) |
| @@ -1063,6 +1067,7 @@ method invocation orders of the involved classes." | |||
| 1063 | ;; | 1067 | ;; |
| 1064 | (define-error 'invalid-slot-name "Invalid slot name") | 1068 | (define-error 'invalid-slot-name "Invalid slot name") |
| 1065 | (define-error 'invalid-slot-type "Invalid slot type") | 1069 | (define-error 'invalid-slot-type "Invalid slot type") |
| 1070 | (define-error 'eieio-read-only "Read-only slot") | ||
| 1066 | (define-error 'unbound-slot "Unbound slot") | 1071 | (define-error 'unbound-slot "Unbound slot") |
| 1067 | (define-error 'inconsistent-class-hierarchy "Inconsistent class hierarchy") | 1072 | (define-error 'inconsistent-class-hierarchy "Inconsistent class hierarchy") |
| 1068 | 1073 | ||
diff --git a/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el b/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el index dfdfb63b584..6f6a1f4f19a 100644 --- a/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el +++ b/test/lisp/emacs-lisp/eieio-tests/eieio-tests.el | |||
| @@ -971,7 +971,7 @@ Subclasses to override slot attributes.") | |||
| 971 | 971 | ||
| 972 | ;;;; Interaction with defstruct | 972 | ;;;; Interaction with defstruct |
| 973 | 973 | ||
| 974 | (cl-defstruct eieio-test--struct a b c) | 974 | (cl-defstruct eieio-test--struct a b (c nil :read-only t)) |
| 975 | 975 | ||
| 976 | (ert-deftest eieio-test-defstruct-slot-value () | 976 | (ert-deftest eieio-test-defstruct-slot-value () |
| 977 | (let ((x (make-eieio-test--struct :a 'A :b 'B :c 'C))) | 977 | (let ((x (make-eieio-test--struct :a 'A :b 'B :c 'C))) |
| @@ -980,7 +980,10 @@ Subclasses to override slot attributes.") | |||
| 980 | (should (eq (eieio-test--struct-b x) | 980 | (should (eq (eieio-test--struct-b x) |
| 981 | (slot-value x 'b))) | 981 | (slot-value x 'b))) |
| 982 | (should (eq (eieio-test--struct-c x) | 982 | (should (eq (eieio-test--struct-c x) |
| 983 | (slot-value x 'c))))) | 983 | (slot-value x 'c))) |
| 984 | (setf (slot-value x 'a) 1) | ||
| 985 | (should (eq (eieio-test--struct-a x) 1)) | ||
| 986 | (should-error (setf (slot-value x 'c) 3) :type 'eieio-read-only))) | ||
| 984 | 987 | ||
| 985 | (provide 'eieio-tests) | 988 | (provide 'eieio-tests) |
| 986 | 989 | ||