* [PATCH] Desktop mode saves mark-ring too verbosely
@ 2013-05-22 3:44 Kelly Dean
2013-11-23 13:40 ` Stefan Monnier
0 siblings, 1 reply; 25+ messages in thread
From: Kelly Dean @ 2013-05-22 3:44 UTC (permalink / raw)
To: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 1400 bytes --]
You can (add-to-list 'desktop-locals-to-save 'mark-ring) and it works, so long as you have the fix for bug 13951 applied. But it's very verbose; for each element of mark-ring for each buffer, it writes an entry like
(let ((mk (make-marker))) (add-hook 'desktop-delay-hook (list 'lambda '() (list 'set-marker mk 123 '(get-buffer "init.el")))) mk)
The result is about 2kB of text to record a standard 16-element mark-ring. The file name is redundant, since it's already written as the first argument for desktop-create-buffer, and the rest of the line could be eliminated by special-casing saving of mark-ring, leaving just a list of marker positions to write into the desktop file, which will typically be less than 100 bytes of text. If you have dozens of file-visiting buffers, this can make the difference between a desktop file that's over 100kB and one that's just a few kB.
The attached patch does this. Surely this qualifies as a tiny change, since it only changes about 5 significant lines.
The "&rest _unsupported" is unnecessary; it just enables forward compatibility with files of version greater than 207. If it were already there, then version 206 code would be able to read version 207 files, and just ignore the mark ring.
Returning result from desktop-create-buffer is unnecessary for desktop mode, but it does no harm, and I need it in some of my other code, so please allow it.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: desktop-mark-ring.patch --]
[-- Type: text/x-diff; name="desktop-mark-ring.patch", Size: 1484 bytes --]
--- emacs-24.3/lisp/desktop.el
+++ emacs-24.3/lisp/desktop.el
@@ -133,7 +133,7 @@
;;; Code:
-(defvar desktop-file-version "206"
+(defvar desktop-file-version "207"
"Version number of desktop file format.
Written into the desktop file and used at desktop read to provide
backward compatibility.")
@@ -694,7 +694,8 @@
(when (member (car locals) loclist)
(setq ll (cons (car locals) ll)))))
(setq locals (cdr locals)))
- ll)))
+ ll)
+ (mapcar 'marker-position mark-ring)))
;; ----------------------------------------------------------------------------
(defun desktop-internal-v2s (value)
@@ -1145,7 +1146,9 @@
buffer-readonly
buffer-misc
&optional
- buffer-locals)
+ buffer-locals
+ buffer-mark-ring
+ &rest _unsupported)
(let ((desktop-file-version file-version)
(desktop-buffer-file-name buffer-filename)
@@ -1233,7 +1236,11 @@
;; an entry of the form `symbol'
(make-local-variable this)
(makunbound this)))
- (setq desktop-buffer-locals (cdr desktop-buffer-locals))))))))
+ (setq desktop-buffer-locals (cdr desktop-buffer-locals)))
+ (unless (< desktop-file-version 207) ;; Don't misinterpret any old custom args
+ (setq mark-ring
+ (mapcar (lambda (p) (set-marker (make-marker) p)) buffer-mark-ring))))
+ result))))
;; ----------------------------------------------------------------------------
;; Backward compatibility -- update parameters to 205 standards.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Desktop mode saves mark-ring too verbosely
2013-05-22 3:44 [PATCH] Desktop mode saves mark-ring too verbosely Kelly Dean
@ 2013-11-23 13:40 ` Stefan Monnier
2015-01-21 12:11 ` Kelly Dean
0 siblings, 1 reply; 25+ messages in thread
From: Stefan Monnier @ 2013-11-23 13:40 UTC (permalink / raw)
To: Kelly Dean; +Cc: emacs-devel
> You can (add-to-list 'desktop-locals-to-save 'mark-ring) and it works, so
> long as you have the fix for bug 13951 applied. But it's very verbose; for
> each element of mark-ring for each buffer, it writes an entry like
> (let ((mk (make-marker))) (add-hook 'desktop-delay-hook (list 'lambda '()
> (list 'set-marker mk 123 '(get-buffer "init.el")))) mk)
> @@ -694,7 +694,8 @@
> (when (member (car locals) loclist)
> (setq ll (cons (car locals) ll)))))
> (setq locals (cdr locals)))
> - ll)))
> + ll)
> + (mapcar 'marker-position mark-ring)))
Having special-case code to print&read some variables is not in itself
a bad idea, but I think we should do it via a table mapping variables to
ad-hoc massaging functions.
Stefan
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Desktop mode saves mark-ring too verbosely
2013-11-23 13:40 ` Stefan Monnier
@ 2015-01-21 12:11 ` Kelly Dean
2015-01-21 15:04 ` Stefan Monnier
0 siblings, 1 reply; 25+ messages in thread
From: Kelly Dean @ 2015-01-21 12:11 UTC (permalink / raw)
To: Stefan Monnier; +Cc: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 713 bytes --]
Stefan Monnier wrote on 23 Nov 2013:
>> You can (add-to-list 'desktop-locals-to-save 'mark-ring) and it works, so
>> long as you have the fix for bug 13951 applied. But it's very verbose; for
>> each element of mark-ring for each buffer, it writes an entry like
>> (let ((mk (make-marker))) (add-hook 'desktop-delay-hook (list 'lambda '()
>> (list 'set-marker mk 123 '(get-buffer "init.el")))) mk)
[snip]
> Having special-case code to print&read some variables is not in itself
> a bad idea, but I think we should do it via a table mapping variables to
> ad-hoc massaging functions.
Ok. Updated patch attached below.
This is more complex than my original patch, but it does what you want (IIUC what you want).
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: desktop-mark-ring-tablized.patch --]
[-- Type: text/x-diff, Size: 2439 bytes --]
--- emacs-24.4/lisp/desktop.el
+++ emacs-24.4/lisp/desktop.el
@@ -135,7 +135,7 @@
(require 'cl-lib)
(require 'frameset)
-(defvar desktop-file-version "206"
+(defvar desktop-file-version "208"
"Version number of desktop file format.
Written into the desktop file and used at desktop read to provide
backward compatibility.")
@@ -628,6 +628,20 @@
"When the desktop file was last modified to the knowledge of this Emacs.
Used to detect desktop file conflicts.")
+(defvar desktop-var-serdes-funs
+ (list (list
+ 'mark-ring
+ (lambda (mr)
+ (mapcar #'marker-position mr))
+ (lambda (bmr)
+ (mapcar (lambda (p)
+ (set-marker (make-marker) p))
+ bmr))))
+ "Table of serdes functions for variables.
+Each record is a list of form: (var serializer deserializer).
+These records can be freely reordered, deleted, or new ones added.
+However, for compatibility, don't modify the functions for existing records.")
+
(defun desktop-owner (&optional dirname)
"Return the PID of the Emacs process that owns the desktop file in DIRNAME.
Return nil if no desktop file found or no Emacs process is using it.
@@ -779,7 +793,12 @@
(push here ll))
((member local loclist)
(push local ll)))))
- ll)))
+ ll)
+ (mapcar (lambda (record)
+ (let ((var (car record)))
+ (list var
+ (funcall (cadr record) (symbol-value var)))))
+ desktop-var-serdes-funs)))
;; ----------------------------------------------------------------------------
(defun desktop--v2s (value)
@@ -1336,7 +1355,9 @@
buffer-readonly
buffer-misc
&optional
- buffer-locals)
+ buffer-locals
+ compacted-vars
+ &rest _unsupported)
(let ((desktop-file-version file-version)
(desktop-buffer-file-name buffer-filename)
@@ -1426,7 +1447,14 @@
(set (car this) (cdr this)))
;; An entry of the form `symbol'.
(make-local-variable this)
- (makunbound this))))))))
+ (makunbound this)))
+ (unless (< desktop-file-version 208) ; Don't misinterpret any old custom args
+ (dolist (record compacted-vars)
+ (let*
+ ((var (car record))
+ (deser-fun (cl-caddr (assq var desktop-var-serdes-funs))))
+ (if deser-fun (set var (funcall deser-fun (cadr record))))))))
+ result))))
;; ----------------------------------------------------------------------------
;; Backward compatibility -- update parameters to 205 standards.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Desktop mode saves mark-ring too verbosely
2015-01-21 12:11 ` Kelly Dean
@ 2015-01-21 15:04 ` Stefan Monnier
2015-01-22 5:43 ` Kelly Dean
0 siblings, 1 reply; 25+ messages in thread
From: Stefan Monnier @ 2015-01-21 15:04 UTC (permalink / raw)
To: Kelly Dean; +Cc: emacs-devel
> This is more complex than my original patch, but it does what you want
> (IIUC what you want).
Looks OK, indeed.
> + (mapcar (lambda (p)
> + (set-marker (make-marker) p))
> + bmr))))
Aka (mapcar #'copy-marker bmr)
Stefan
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Desktop mode saves mark-ring too verbosely
2015-01-21 15:04 ` Stefan Monnier
@ 2015-01-22 5:43 ` Kelly Dean
2015-01-22 8:20 ` Ivan Shmakov
0 siblings, 1 reply; 25+ messages in thread
From: Kelly Dean @ 2015-01-22 5:43 UTC (permalink / raw)
To: Stefan Monnier; +Cc: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 277 bytes --]
Stefan Monnier wrote:
>> + (mapcar (lambda (p)
>> + (set-marker (make-marker) p))
>> + bmr))))
>
> Aka (mapcar #'copy-marker bmr)
I forgot copy-marker existed. Updated patch attached.
FYI I'm not a committer, so I'm only sending my patches to the mailing list.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: desktop-mark-ring-tablized-1.patch --]
[-- Type: text/x-diff, Size: 2395 bytes --]
--- emacs-24.4/lisp/desktop.el
+++ emacs-24.4/lisp/desktop.el
@@ -135,7 +135,7 @@
(require 'cl-lib)
(require 'frameset)
-(defvar desktop-file-version "206"
+(defvar desktop-file-version "208"
"Version number of desktop file format.
Written into the desktop file and used at desktop read to provide
backward compatibility.")
@@ -628,6 +628,18 @@
"When the desktop file was last modified to the knowledge of this Emacs.
Used to detect desktop file conflicts.")
+(defvar desktop-var-serdes-funs
+ (list (list
+ 'mark-ring
+ (lambda (mr)
+ (mapcar #'marker-position mr))
+ (lambda (mr)
+ (mapcar #'copy-marker mr))))
+ "Table of serdes functions for variables.
+Each record is a list of form: (var serializer deserializer).
+These records can be freely reordered, deleted, or new ones added.
+However, for compatibility, don't modify the functions for existing records.")
+
(defun desktop-owner (&optional dirname)
"Return the PID of the Emacs process that owns the desktop file in DIRNAME.
Return nil if no desktop file found or no Emacs process is using it.
@@ -779,7 +791,12 @@
(push here ll))
((member local loclist)
(push local ll)))))
- ll)))
+ ll)
+ (mapcar (lambda (record)
+ (let ((var (car record)))
+ (list var
+ (funcall (cadr record) (symbol-value var)))))
+ desktop-var-serdes-funs)))
;; ----------------------------------------------------------------------------
(defun desktop--v2s (value)
@@ -1336,7 +1353,9 @@
buffer-readonly
buffer-misc
&optional
- buffer-locals)
+ buffer-locals
+ compacted-vars
+ &rest _unsupported)
(let ((desktop-file-version file-version)
(desktop-buffer-file-name buffer-filename)
@@ -1426,7 +1445,14 @@
(set (car this) (cdr this)))
;; An entry of the form `symbol'.
(make-local-variable this)
- (makunbound this))))))))
+ (makunbound this)))
+ (unless (< desktop-file-version 208) ; Don't misinterpret any old custom args
+ (dolist (record compacted-vars)
+ (let*
+ ((var (car record))
+ (deser-fun (cl-caddr (assq var desktop-var-serdes-funs))))
+ (if deser-fun (set var (funcall deser-fun (cadr record))))))))
+ result))))
;; ----------------------------------------------------------------------------
;; Backward compatibility -- update parameters to 205 standards.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Desktop mode saves mark-ring too verbosely
2015-01-22 5:43 ` Kelly Dean
@ 2015-01-22 8:20 ` Ivan Shmakov
2015-01-23 13:20 ` Kelly Dean
0 siblings, 1 reply; 25+ messages in thread
From: Ivan Shmakov @ 2015-01-22 8:20 UTC (permalink / raw)
To: emacs-devel; +Cc: Stefan Monnier
>>>>> Kelly Dean <kelly@prtime.org> writes:
[…]
> @@ -628,6 +628,18 @@
> "When the desktop file was last modified to the knowledge of this Emacs.
> Used to detect desktop file conflicts.")
> +(defvar desktop-var-serdes-funs
I’d rather see it use the unabbreviated ‘-functions’ suffix.
(Also, aren’t “serialization” and “deserialization” often
referred to as “writing” and “reading” in the dialects of Lisp?)
> + (list (list
> + 'mark-ring
> + (lambda (mr)
> + (mapcar #'marker-position mr))
> + (lambda (mr)
> + (mapcar #'copy-marker mr))))
> + "Table of serdes functions for variables.
It doesn’t look like a common abbreviation, so I guess
“serializer, deserializer” should rather be spelled in full.
(And even more so when it comes to the first line of a
docstring.)
> +Each record is a list of form: (var serializer deserializer).
> +These records can be freely reordered, deleted, or new ones added.
> +However, for compatibility, don't modify the functions for existing records.")
> +
[…]
--
FSF associate member #7257 np. Machine Gun — Flotsam and Jetsam … 230E 334A
^ permalink raw reply [flat|nested] 25+ messages in thread
* Rant - Elisp terminology is deceptive
@ 2015-01-23 2:59 Kelly Dean
2015-01-23 20:15 ` Stefan Monnier
0 siblings, 1 reply; 25+ messages in thread
From: Kelly Dean @ 2015-01-23 2:59 UTC (permalink / raw)
To: emacs-devel
I wasted an hour today re-discovering the fact that (eval (car (get 'foo 'standard-value))), not (default-value 'foo), returns the default value of 'foo. I learned this lesson before, but the word ‟default” is so suggestive of meaning «default» that I forgot that it doesn't actually mean «default» in Emacs. I even remembered setq-default, but cognitive dissonance from the absurdity of its name prevented me from remembering that default-value has the same problem.
For the value of a symbol in the global context, how about using the word ‟global”?
Ask any normal English-speaker for an antonym of ‟local”. He won't say ‟default”. He'll say ‟remote” or ‟global” or some such.
Ask him for an antonym of ‟default”. He won't say ‟local”. He'll say ‟non-standard” or ‟customized” or some such.
Inflict Emacs upon him for a few months, then ask him what's the difference between a ‟standard value” and a ‟default value”. He won't know. Even after writing a thousand lines of Elisp.
Tell him that the default value of shift-select-mode is t. Then do (setq shift-select-mode nil), and ask him what the default value is. He'll say ‟t”, not ‟nil”. Ask him what changed, and he'll say shift-select-mode is no longer set to the default value. Then show him what (default-value shift-select-mode) returns, and he'll tell you it must be a bug.
Since ‟default” is already misused to mean «global», it can't be changed to mean «standard», since that would cause even more confusion. ‟Standard” can stay the way it is. ‟Buffer-local” can too. But please stop using the word ‟default” for «global»; use ‟global”. There's already precedence in Emacs: describe-variable calls it ‟global”.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Desktop mode saves mark-ring too verbosely
2015-01-22 8:20 ` Ivan Shmakov
@ 2015-01-23 13:20 ` Kelly Dean
2015-01-23 14:09 ` Ivan Shmakov
2015-01-24 3:08 ` Stephen J. Turnbull
0 siblings, 2 replies; 25+ messages in thread
From: Kelly Dean @ 2015-01-23 13:20 UTC (permalink / raw)
To: Ivan Shmakov; +Cc: emacs-devel
Ivan Shmakov wrote:
>> +(defvar desktop-var-serdes-funs
[snip]
> aren’t “serialization” and “deserialization” often
> referred to as “writing” and “reading” in the dialects of Lisp?
Yes, but I intentionally avoided those terms because this table is for functions that don't necessarily just print and read in the normal Lisp sense. E.g. mark-ring contains markers, and a marker contains both a position and a reference to the relevant buffer, so simply printing mark-ring in the Lisp sense would involve printing both the positions and the buffer references, but its serializer function in this table outputs only the positions. The entire point of my patch is to avoid the Lisp sense of printing, because printing the buffer references is far too verbose.
> It doesn’t look like a common abbreviation,
It's a common abbreviation for parallel↔serial conversion circuits, which are reasonably analogous to functions that convert program data to/from a text stream. And circuitry is a domain for which it's common to share terminology with software.
> so I guess
> “serializer, deserializer” should rather be spelled in full.
This table is something that only programmers, not users, will need to understand or modify, so using a technical abbreviation isn't a problem. Emacs already has abbreviated names such as ⌜fboundp⌝ and ⌜fmakunbound⌝ for programmer-only things, instead of ⌜function-bound-predicate⌝ and ⌜function-make-unbound⌝. So if anything, ⌜funs⌝ isn't abbreviated _enough_. ;-)
Spelling out ⌜desktop-variable-serialization-deserialization-functions⌝ would be ironic, considering the purpose of my patch.
BTW, you quoted only me, but you CCed only Stefan. I almost missed your message, until I checked the mailing list.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Desktop mode saves mark-ring too verbosely
2015-01-23 13:20 ` Kelly Dean
@ 2015-01-23 14:09 ` Ivan Shmakov
2015-01-24 3:08 ` Stephen J. Turnbull
1 sibling, 0 replies; 25+ messages in thread
From: Ivan Shmakov @ 2015-01-23 14:09 UTC (permalink / raw)
To: emacs-devel
>>>>> Kelly Dean <kelly@prtime.org> writes:
>>>>> Ivan Shmakov wrote:
[…]
>>> +(defvar desktop-var-serdes-funs
[…]
>>> + "Table of serdes functions for variables.
>> It doesn’t look like a common abbreviation,
> It's a common abbreviation for parallel ↔ serial conversion circuits,
> which are reasonably analogous to functions that convert program data
> to/from a text stream. And circuitry is a domain for which it's
> common to share terminology with software.
Incidentally, reading and development of digital circuits is one
of my hobbies. Yet, I don’t think I’ve ever seen such an
abbreviation before in that domain, either.
>> so I guess “serializer, deserializer” should rather be spelled in
>> full.
> This table is something that only programmers, not users, will need
> to understand or modify, so using a technical abbreviation isn't a
> problem. Emacs already has abbreviated names such as ⌜fboundp⌝ and
> ⌜fmakunbound⌝ for programmer-only things, instead of
> ⌜function-bound-predicate⌝ and ⌜function-make-unbound⌝.
Still, their respective docstrings spell the term in full:
(fboundp SYMBOL): Return t if SYMBOL's function definition is not void.
(fmakunbound SYMBOL): Make SYMBOL's function definition be void.
Contrary to the docstring proposed.
> So if anything, ⌜funs⌝ isn't abbreviated _enough_. ;-)
Then just drop that part.
[…]
> BTW, you quoted only me, but you CCed only Stefan.
It was unintended, sorry. Unless under special circumstances,
I post my followups strictly to the list, – not to the
participants of the discussion directly.
> I almost missed your message, until I checked the mailing list.
(Hope you’ll check the mailing list this time, too.)
--
FSF associate member #7257 np. Birdeto — Helena Melnikova … B6A0 230E 334A
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Rant - Elisp terminology is deceptive
2015-01-23 2:59 Rant - Elisp terminology is deceptive Kelly Dean
@ 2015-01-23 20:15 ` Stefan Monnier
2015-01-24 0:41 ` Kelly Dean
0 siblings, 1 reply; 25+ messages in thread
From: Stefan Monnier @ 2015-01-23 20:15 UTC (permalink / raw)
To: Kelly Dean; +Cc: emacs-devel
> Since ‟default” is already misused to mean «global», it can't be changed to
> mean «standard», since that would cause even more confusion. ‟Standard” can
> stay the way it is. ‟Buffer-local” can too. But please stop using the word
> ‟default” for «global»; use ‟global”. There's already precedence in Emacs:
> describe-variable calls it ‟global”.
I tend to agree. This "default-value" and "setq-default" dates back
to the very beginning of time, tho.
Stefan
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Rant - Elisp terminology is deceptive
2015-01-23 20:15 ` Stefan Monnier
@ 2015-01-24 0:41 ` Kelly Dean
2015-01-24 0:48 ` Óscar Fuentes
2015-01-24 3:28 ` Stephen J. Turnbull
0 siblings, 2 replies; 25+ messages in thread
From: Kelly Dean @ 2015-01-24 0:41 UTC (permalink / raw)
To: Stefan Monnier; +Cc: emacs-devel
Stefan Monnier wrote:
> I tend to agree. This "default-value" and "setq-default" dates back
> to the very beginning of time, tho.
Would renaming them be acceptable, so long as the old names are kept as aliases for backward compatibility? I don't think the names ⌜global-value⌝, ⌜setq-global⌝, and ⌜set-global⌝ would cause any confusion with any other concepts in Emacs, and they're unlikely to conflict with anybody's custom code.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Rant - Elisp terminology is deceptive
2015-01-24 0:41 ` Kelly Dean
@ 2015-01-24 0:48 ` Óscar Fuentes
2015-01-24 3:28 ` Stephen J. Turnbull
1 sibling, 0 replies; 25+ messages in thread
From: Óscar Fuentes @ 2015-01-24 0:48 UTC (permalink / raw)
To: emacs-devel
Kelly Dean <kelly@prtime.org> writes:
> Stefan Monnier wrote:
>> I tend to agree. This "default-value" and "setq-default" dates back
>> to the very beginning of time, tho.
>
> Would renaming them be acceptable, so long as the old names are kept
> as aliases for backward compatibility? I don't think the names
> ⌜global-value⌝, ⌜setq-global⌝, and ⌜set-global⌝ would cause any
> confusion with any other concepts in Emacs, and they're unlikely to
> conflict with anybody's custom code.
From etc/NEWS.18
** Functions `global-set' and `global-value' deleted.
These functions were never used except by mistake by users expecting
the functionality of `set-default' and `default-value'.
:-)
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] Desktop mode saves mark-ring too verbosely
2015-01-23 13:20 ` Kelly Dean
2015-01-23 14:09 ` Ivan Shmakov
@ 2015-01-24 3:08 ` Stephen J. Turnbull
2015-01-24 23:30 ` Elisp terminology (was: Re: [PATCH] Desktop mode saves mark-ring too verbosely) Kelly Dean
1 sibling, 1 reply; 25+ messages in thread
From: Stephen J. Turnbull @ 2015-01-24 3:08 UTC (permalink / raw)
To: Kelly Dean; +Cc: Ivan Shmakov, emacs-devel
Kelly Dean writes:
> > It doesn’t look like a common abbreviation,
>
> It's a common abbreviation for parallel↔serial conversion circuits,
> which are reasonably analogous to functions that convert program
> data to/from a text stream. And circuitry is a domain for which
> it's common to share terminology with software.
Please don't add new abbreviations. The docstring and/or comments can
indicate that "serializer" stands for both directions if you really
need a shorter variable name. Or use "serialization", which is
somewhat more ambiguous about including "deserialization".
> This table is something that only programmers, not users,
The point of free software is that there's no such distinction worth
making. Whether one agrees philosphically or not, it makes sense to
take advantage of the "many eyes".
> will need to understand or modify, so using a technical
> abbreviation isn't a problem. Emacs already has abbreviated names
> such as ⌜fboundp⌝ and ⌜fmakunbound⌝ for programmer-only things,
> instead of ⌜function-bound-predicate⌝ and ⌜function-make-unbound⌝.
And the recent trend is to deprecate such ancient usage, including the
venerable `car', `cdr', and `cons'.
> Spelling out
> ⌜desktop-variable-serialization-deserialization-functions⌝ would be
> ironic, considering the purpose of my patch.
I thought your patch was a refactoring. That doesn't necessarily mean
code (or code components) are shorter, although it's often a happy
accidental outcome.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Rant - Elisp terminology is deceptive
2015-01-24 0:41 ` Kelly Dean
2015-01-24 0:48 ` Óscar Fuentes
@ 2015-01-24 3:28 ` Stephen J. Turnbull
2015-01-24 8:51 ` Eli Zaretskii
2015-01-24 10:30 ` Kelly Dean
1 sibling, 2 replies; 25+ messages in thread
From: Stephen J. Turnbull @ 2015-01-24 3:28 UTC (permalink / raw)
To: Kelly Dean; +Cc: Stefan Monnier, emacs-devel
Kelly Dean writes:
> Stefan Monnier wrote:
> > I tend to agree.
I also agree that "default" is worse than "global", but "global" is
not obviously appropriate (to me anyway, obviously Kelly likes it
fine).
> > This "default-value" and "setq-default" dates back to the very
> > beginning of time, tho.
>
> Would renaming them be acceptable, so long as the old names are
> kept as aliases for backward compatibility? I don't think the names
> ⌜global-value⌝, ⌜setq-global⌝, and ⌜set-global⌝ would cause any
> confusion with any other concepts in Emacs, and they're unlikely to
> conflict with anybody's custom code.
Please don't. Buffer-local values are global values in the usual
sense that they are instance-wide and can be accessed in local context
if not shadowed by let-bindings and the like. I understand your
mileage varies, but I don't think it's a big enough improvement to
justify having an alias, with neither being deprecated. And I
definitely don't think it's a big enough improvement to justify
obsoleting the "default" versions.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Rant - Elisp terminology is deceptive
2015-01-24 3:28 ` Stephen J. Turnbull
@ 2015-01-24 8:51 ` Eli Zaretskii
2015-01-24 10:32 ` Kelly Dean
2015-01-24 10:30 ` Kelly Dean
1 sibling, 1 reply; 25+ messages in thread
From: Eli Zaretskii @ 2015-01-24 8:51 UTC (permalink / raw)
To: Stephen J. Turnbull; +Cc: kelly, monnier, emacs-devel
> From: "Stephen J. Turnbull" <stephen@xemacs.org>
> Date: Sat, 24 Jan 2015 12:28:21 +0900
> Cc: Stefan Monnier <monnier@iro.umontreal.ca>, emacs-devel@gnu.org
>
> > > This "default-value" and "setq-default" dates back to the very
> > > beginning of time, tho.
> >
> > Would renaming them be acceptable, so long as the old names are
> > kept as aliases for backward compatibility? I don't think the names
> > ⌜global-value⌝, ⌜setq-global⌝, and ⌜set-global⌝ would cause any
> > confusion with any other concepts in Emacs, and they're unlikely to
> > conflict with anybody's custom code.
>
> Please don't.
Yes, please let's not. It's too late to introduce changes in that
terminology.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Rant - Elisp terminology is deceptive
2015-01-24 3:28 ` Stephen J. Turnbull
2015-01-24 8:51 ` Eli Zaretskii
@ 2015-01-24 10:30 ` Kelly Dean
2015-01-24 11:03 ` David Kastrup
1 sibling, 1 reply; 25+ messages in thread
From: Kelly Dean @ 2015-01-24 10:30 UTC (permalink / raw)
To: Stephen J. Turnbull; +Cc: emacs-devel
Stephen J. Turnbull wrote:
> Buffer-local values are global values in the usual
> sense that they are instance-wide and can be accessed in local context
> if not shadowed by let-bindings and the like.
Function parameters (or a closure's parameters and environment variables) are global variables in the sense that they're ‟instance-wide” (within the entire function or closure) and can be accessed in local context if not shadowed by let-bindings.
But «within an entire function or closure» isn't really instance-wide? Well neither is «within an entire buffer».
The global environment is the outermost one. A buffer's environment is not. There's only one global environment. There can be multiple buffers and multiple closures, each with its own environment. ‟Buffer-local” is a perfectly good term for buffer-locals. Calling them ‟global” would be misleading, and it's good that Emacs doesn't do that.
‟Global” is the right term for globals.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Rant - Elisp terminology is deceptive
2015-01-24 8:51 ` Eli Zaretskii
@ 2015-01-24 10:32 ` Kelly Dean
2015-01-24 11:26 ` Eli Zaretskii
0 siblings, 1 reply; 25+ messages in thread
From: Kelly Dean @ 2015-01-24 10:32 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: emacs-devel
> It's too late to introduce changes in that terminology.
Why?
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Rant - Elisp terminology is deceptive
2015-01-24 10:30 ` Kelly Dean
@ 2015-01-24 11:03 ` David Kastrup
2015-01-24 23:24 ` Kelly Dean
0 siblings, 1 reply; 25+ messages in thread
From: David Kastrup @ 2015-01-24 11:03 UTC (permalink / raw)
To: Kelly Dean; +Cc: Stephen J. Turnbull, emacs-devel
Kelly Dean <kelly@prtime.org> writes:
> Stephen J. Turnbull wrote:
>> Buffer-local values are global values in the usual
>> sense that they are instance-wide and can be accessed in local context
>> if not shadowed by let-bindings and the like.
>
> Function parameters (or a closure's parameters and environment
> variables) are global variables in the sense that they're
> ‟instance-wide” (within the entire function or closure) and can be
> accessed in local context if not shadowed by let-bindings.
>
> But «within an entire function or closure» isn't really instance-wide?
> Well neither is «within an entire buffer».
We are not talking about "within an entire buffer". Emacs has a notion
of a "current buffer". There is no hierarchy or stack or nesting
involved: the current buffer setting swaps out variables in global
scope. It does not matter which module or buffer or context your global
variables have been defined in.
> The global environment is the outermost one. A buffer's environment is
> not.
That confusion seems to be the most compelling reason _not_ to mess with
the terminology in order not to cause additional confusion. A buffer
does not have an "environment". It has a list of global variable values
to substitute whenever it is made current. There is always exactly one
current buffer. You cannot _not_ have a current buffer:
emacs -Q --batch --eval '(message "%S" (current-buffer))'
#<buffer *scratch*>
> There's only one global environment. There can be multiple buffers and
> multiple closures, each with its own environment. ‟Buffer-local” is a
> perfectly good term for buffer-locals. Calling them ‟global” would be
> misleading, and it's good that Emacs doesn't do that.
>
> ‟Global” is the right term for globals.
And buffer-local variables _are_ buffer-local versions of _global_
variables. They are not scoped. With setq-default you are not setting
a value that is in any manner more or less global than a buffer-local
setting. It is a separate symbol slot only accessible via special
commands or when no buffer-local setting exists.
--
David Kastrup
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Rant - Elisp terminology is deceptive
2015-01-24 10:32 ` Kelly Dean
@ 2015-01-24 11:26 ` Eli Zaretskii
0 siblings, 0 replies; 25+ messages in thread
From: Eli Zaretskii @ 2015-01-24 11:26 UTC (permalink / raw)
To: Kelly Dean; +Cc: emacs-devel
> From: Kelly Dean <kelly@prtime.org>
> CC: emacs-devel@gnu.org
> Date: Sat, 24 Jan 2015 10:32:53 +0000
>
> > It's too late to introduce changes in that terminology.
>
> Why?
Because generations of ELisp programmers are used to it.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Rant - Elisp terminology is deceptive
2015-01-24 11:03 ` David Kastrup
@ 2015-01-24 23:24 ` Kelly Dean
2015-01-25 9:16 ` David Kastrup
0 siblings, 1 reply; 25+ messages in thread
From: Kelly Dean @ 2015-01-24 23:24 UTC (permalink / raw)
To: David Kastrup; +Cc: emacs-devel
David Kastrup wrote:
> A buffer does not have an "environment".
What do you call the thing that lists the bindings of buffer-local variables to values? The standard term for a list of bindings of variables to values that's used for resolving variable references, both in Lisp and elsewhere, is ‟environment”.
> It has a list of global variable values
> to substitute whenever it is made current.
You mean like a closure can have? (A closure's environment can also have variables with names that aren't names of global variables, but that's not the point here.)
(setq foo
(lexical-let ((shift-select-mode 'bar))
(lambda () shift-select-mode)))
(funcall foo) → bar
> buffer-local variables _are_ buffer-local versions of _global_
> variables.
shift-select-mode above is a closure-local version of a global variable.
> With setq-default you are not setting
> a value that is in any manner more or less global than a buffer-local
> setting.
setq-default sets the global variable, which is visible in other buffers (unless they shadow it with their own buffer-locals).
A buffer-local variable is not visible in other buffers.
I don't know how buffer-locals are implemented internally, but from a user's (and Elisp programmer's) point of view, a buffer has an environment with variables that shadow global variables. If the value of each variable in that environment is stored as part of the structure that stores the value of the same-named global variable rather than being stored in a separate list of bindings for the environment, that's irrelevant. The effect is the same.
The help system agrees with me. It doesn't call buffer-locals ‟global”. It _contrasts_ buffer-locals and globals. E.g. describe-variable for mark-active tells me:
mark-active is a variable defined in `buffer.c'.
Its value is t
Local in buffer *Help*; global value is nil
^ permalink raw reply [flat|nested] 25+ messages in thread
* Elisp terminology (was: Re: [PATCH] Desktop mode saves mark-ring too verbosely)
2015-01-24 3:08 ` Stephen J. Turnbull
@ 2015-01-24 23:30 ` Kelly Dean
2015-01-25 9:49 ` Elisp terminology David Kastrup
0 siblings, 1 reply; 25+ messages in thread
From: Kelly Dean @ 2015-01-24 23:30 UTC (permalink / raw)
To: Stephen J. Turnbull; +Cc: emacs-devel
Stephen J. Turnbull wrote:
>> will need to understand or modify, so using a technical
>> abbreviation isn't a problem. Emacs already has abbreviated names
>> such as ⌜fboundp⌝ and ⌜fmakunbound⌝ for programmer-only things,
>> instead of ⌜function-bound-predicate⌝ and ⌜function-make-unbound⌝.
>
> And the recent trend is to deprecate such ancient usage, including the
> venerable `car', `cdr', and `cons'.
Look what happened when I proposed changing the names of set-default, setq-default, and default-value. They're misleading, but you and Eli say they're too old to change. IOW, bugs with seniority are features.
The names of car and cdr are even older. And they're not misleading; they're just archaic. There's both less need and less ability to change them than there is to change the former three.
And yes, the abbreviations ⌜cons⌝, ⌜fboundp⌝, and ⌜fmakunbound⌝ are old, but they're neither misleading nor archaic. I'm a good benchmark, since I'm easily fooled by misleading names and I have bad memory, yet these names don't cause me problems.
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Rant - Elisp terminology is deceptive
2015-01-24 23:24 ` Kelly Dean
@ 2015-01-25 9:16 ` David Kastrup
2015-01-26 3:52 ` Kelly Dean
0 siblings, 1 reply; 25+ messages in thread
From: David Kastrup @ 2015-01-25 9:16 UTC (permalink / raw)
To: Kelly Dean; +Cc: emacs-devel
Kelly Dean <kelly@prtime.org> writes:
> David Kastrup wrote:
>> A buffer does not have an "environment".
>
> What do you call the thing that lists the bindings of buffer-local
> variables to values? The standard term for a list of bindings of
> variables to values that's used for resolving variable references,
> both in Lisp and elsewhere, is ‟environment”.
>
>> It has a list of global variable values
>> to substitute whenever it is made current.
>
> You mean like a closure can have? (A closure's environment can also have variables with names that aren't names of global variables, but that's not the point here.)
> (setq foo
> (lexical-let ((shift-select-mode 'bar))
> (lambda () shift-select-mode)))
> (funcall foo) → bar
Closures nest. Buffers don't. And there always is one current buffer.
Closures are part of a lexical environment. Buffers aren't.
>> buffer-local variables _are_ buffer-local versions of _global_
>> variables.
>
> shift-select-mode above is a closure-local version of a global
> variable.
Not at all. It is not related to the global variable in any way. If
you do
(disassemble (byte-compile foo)) you get
byte code:
args: (&rest --cl-rest--)
0 constant apply
1 constant <compiled-function>
args: (G42200)
0 varref G42200
1 symbol-value
2 return
2 constant --shift-select-mode--
3 varref --cl-rest--
4 call 3
5 return
which is rather awful. But the salient point is that
--shift-select-mode-- is a generated symbol (with value 'bar) not in any
way related to the global variable shift-select-mode.
>> With setq-default you are not setting
>> a value that is in any manner more or less global than a buffer-local
>> setting.
>
> setq-default sets the global variable, which is visible in other
> buffers (unless they shadow it with their own buffer-locals).
> A buffer-local variable is not visible in other buffers.
The default value and the global value are part of the same symbol and
accessed with different commands.
> I don't know how buffer-locals are implemented internally, but from a
> user's (and Elisp programmer's) point of view, a buffer has an
> environment with variables that shadow global variables.
Again, the buffer does not provide scoping. It is the setting of
(current-buffer) that decides which buffer-local values are active.
> If the value of each variable in that environment is stored as part of
> the structure that stores the value of the same-named global variable
> rather than being stored in a separate list of bindings for the
> environment, that's irrelevant. The effect is the same.
There is no nesting of scopes involved here. At any given time, only
one buffer's global variable are active. That is similar to global
static variables in C: they are not nested. Instead, one compilation
unit at a time may provide a value. C does not have defaults for global
static variables: it is an error to declare the same name as global
external and global static.
Elisp, in contrast, provides two value slots for that purpose.
> The help system agrees with me. It doesn't call buffer-locals
> ‟global”. It _contrasts_ buffer-locals and
> globals. E.g. describe-variable for mark-active tells me: mark-active
> is a variable defined in `buffer.c'. Its value is t Local in buffer
> *Help*; global value is nil
It does not seem like a good idea to spread the confusion, however.
--
David Kastrup
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Elisp terminology
2015-01-24 23:30 ` Elisp terminology (was: Re: [PATCH] Desktop mode saves mark-ring too verbosely) Kelly Dean
@ 2015-01-25 9:49 ` David Kastrup
0 siblings, 0 replies; 25+ messages in thread
From: David Kastrup @ 2015-01-25 9:49 UTC (permalink / raw)
To: Kelly Dean; +Cc: Stephen J. Turnbull, emacs-devel
Kelly Dean <kelly@prtime.org> writes:
> Stephen J. Turnbull wrote:
>>> will need to understand or modify, so using a technical
>>> abbreviation isn't a problem. Emacs already has abbreviated names
>>> such as ⌜fboundp⌝ and ⌜fmakunbound⌝ for programmer-only things,
>>> instead of ⌜function-bound-predicate⌝ and ⌜function-make-unbound⌝.
>>
>> And the recent trend is to deprecate such ancient usage, including the
>> venerable `car', `cdr', and `cons'.
>
> Look what happened when I proposed changing the names of set-default,
> setq-default, and default-value. They're misleading,
No, they aren't, but you are not willing to hear any explanation in
conflict with your preconceptions.
> but you and Eli say they're too old to change. IOW, bugs with
> seniority are features.
>
> The names of car and cdr are even older. And they're not misleading;
> they're just archaic.
I have my problems seeing how "Contents of address register" and
"Contents of decrement register" are accurate concerning the current
implementations. In their _archaic_ sense, those terms are not
accurate. It's just that they have grown into terms of their own.
> There's both less need and less ability to change them than there is
> to change the former three.
In contrast to car/cdr however, the _default_ value is still an accurate
description.
> And yes, the abbreviations ⌜cons⌝, ⌜fboundp⌝, and ⌜fmakunbound⌝ are
> old, but they're neither misleading nor archaic.
fboundp is sort of an archaic feature of the language. Lisp symbols
have 4 slots by default: value, function value, property list, name.
In Scheme, symbols don't have any slot. They are semantically the same
as keywords, just being an internment of their name. That makes it
possible to implement a module system establishing the relation between
symbols and values in the _global_ lexical space.
> I'm a good benchmark, since I'm easily fooled by misleading names and
> I have bad memory, yet these names don't cause me problems.
The problem is that you consider yourself the only benchmark, not just
for the naming but also for the meaning and implementation of terms.
That's not unusual for programmers, which is why there are regularly
scheduled shouting events under the title of "standards committee".
With regard to Emacs Lisp, we don't have such official events.
--
David Kastrup
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Rant - Elisp terminology is deceptive
2015-01-25 9:16 ` David Kastrup
@ 2015-01-26 3:52 ` Kelly Dean
2015-01-26 8:28 ` Thien-Thi Nguyen
0 siblings, 1 reply; 25+ messages in thread
From: Kelly Dean @ 2015-01-26 3:52 UTC (permalink / raw)
To: David Kastrup; +Cc: emacs-devel
David Kastrup wrote:
> Closures nest. Buffers don't.
If you define nesting to be a required attribute of environments, then of course, by definition, things that don't nest aren't environments. But it seems strange to define them that way. Maybe this is a basic computer science truth I just missed.
How about a language that provides only global variables? No locals of any kind. Would you say that its global ‟environment” isn't really an environment, because there's nothing to nest it in or nest in it?
For Elisp, although buffers' environments can't nest in other buffers' environments, they do nest in something (the global environment, which I guess you would call the ⌜default environment⌝), and there are environments (of closures) that can nest in them. You can have a global variable, shadowed by a buffer-local, shadowed by a closure-local.
> Closures are part of a lexical environment. Buffers aren't.
An environment can only have one binding for a particular name, which means that if the name ⌜shift-select-mode⌝ can be bound to t in the global/default environment, to nil in a buffer-local environment, and to 'bar in a closure's environment, then those are necessarily three different environments. If there weren't, then there couldn't simultaneously be three bindings for the same name.
Even if you have only global scope and dynamic extent, not lexical scope and closures, every «let» still creates a new environment at runtime that nests both in the global environment and in every earlier «let» being evaluated, and each variable bound in an environment shadows every variable with the same name in every outer environment. Even if this is implemented by storing the current environment in place of outer ones and pushing the latter onto a stack, the effect is the same.
I think you're using ‟environment” to mean something different than I am. Maybe I'm using it wrong.
> --shift-select-mode-- is a generated symbol (with value 'bar) not in any
> way related to the global variable shift-select-mode.
It has a relationship to the global variable that a buffer-local variable also has: it shadows it.
> Again, the buffer does not provide scoping.
IIUC, you mean that lexically, a buffer-local variable is defined in the global scope. But my point is that its runtime instances aren't in the global environment; they're in buffers' environments. If there were only one environment, then there could be only one instance of the variable, meaning different buffers couldn't have different values for it.
If I do (setq-default shift-select-mode nil), and in three buffers I do
(setq-local shift-select-mode (random)), how many runtime variables do I have? Do you say I have only one or two? If so, which environment(s) is it bound in?
I say I have four, each in a separate environment.
David Kastrup wrote in a different message:
>> Look what happened when I proposed changing the names of set-default,
>> setq-default, and default-value. They're misleading,
>
> No, they aren't, but you are not willing to hear any explanation in
> conflict with your preconceptions.
Of course, this misleadingness is a matter of perception. The names are certainly misleading to me, despite your explanation. I thought everybody would perceive them as misleading, but obviously I was wrong about that, since you don't. At least Stephen and Eli only said the names are too old to change, not that they're not misleading.
If I'm just part of a minority that fails to understand that ⌜default⌝ is the most sensible term for the Emacs environment whose variables don't shadow variables in any other environment, then of course the term shouldn't be changed.
But if I'm part of a majority that fails to understand, then resistance is futile. You will be assimilated.
> I have my problems seeing how "Contents of address register" and
> "Contents of decrement register" are accurate concerning the current
> implementations.
Of course, those terms are not accurate at all now. But they used to be. That's why I said they're archaic.
> In their _archaic_ sense, those terms are not accurate.
Probably you mean the same thing I do, just phrased the opposite.
> fboundp is sort of an archaic feature of the language.
But given the feature, the name isn't archaic. If I had to choose a name today for that function, ⌜fboundp⌝ would be a fine choice. That's all I meant.
> there are regularly
> scheduled shouting events under the title of "standards committee".
>
> With regard to Emacs Lisp, we don't have such official events.
Isn't that what emacs-devel is for? ;-)
^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Rant - Elisp terminology is deceptive
2015-01-26 3:52 ` Kelly Dean
@ 2015-01-26 8:28 ` Thien-Thi Nguyen
0 siblings, 0 replies; 25+ messages in thread
From: Thien-Thi Nguyen @ 2015-01-26 8:28 UTC (permalink / raw)
To: emacs-devel
[-- Attachment #1: Type: text/plain, Size: 1073 bytes --]
() Kelly Dean <kelly@prtime.org>
() Mon, 26 Jan 2015 03:52:17 +0000
If I'm just part of a minority that fails to understand that
⌜default⌝ is the most sensible term for the Emacs environment
whose variables don't shadow variables in any other
environment, then of course the term shouldn't be changed.
But if I'm part of a majority that fails to understand, then
resistance is futile. You will be assimilated.
This particular line of thinking has led to "hacker" being a
denigration in society at large, among other more serious
atrocities.
I think if you program in C, it is easy to see how ‘switch’
.. ‘default:’ illustrates the dynamic aspect of the concept.
Rather than "this thing does not shadow", i see "this action is
the last recourse".
[Insert Pirsig-esque ruminations, here...]
--
Thien-Thi Nguyen
GPG key: 4C807502
(if you're human and you know it)
read my lisp: (responsep (questions 'technical)
(not (via 'mailing-list)))
=> nil
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 197 bytes --]
^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2015-01-26 8:28 UTC | newest]
Thread overview: 25+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-05-22 3:44 [PATCH] Desktop mode saves mark-ring too verbosely Kelly Dean
2013-11-23 13:40 ` Stefan Monnier
2015-01-21 12:11 ` Kelly Dean
2015-01-21 15:04 ` Stefan Monnier
2015-01-22 5:43 ` Kelly Dean
2015-01-22 8:20 ` Ivan Shmakov
2015-01-23 13:20 ` Kelly Dean
2015-01-23 14:09 ` Ivan Shmakov
2015-01-24 3:08 ` Stephen J. Turnbull
2015-01-24 23:30 ` Elisp terminology (was: Re: [PATCH] Desktop mode saves mark-ring too verbosely) Kelly Dean
2015-01-25 9:49 ` Elisp terminology David Kastrup
-- strict thread matches above, loose matches on Subject: below --
2015-01-23 2:59 Rant - Elisp terminology is deceptive Kelly Dean
2015-01-23 20:15 ` Stefan Monnier
2015-01-24 0:41 ` Kelly Dean
2015-01-24 0:48 ` Óscar Fuentes
2015-01-24 3:28 ` Stephen J. Turnbull
2015-01-24 8:51 ` Eli Zaretskii
2015-01-24 10:32 ` Kelly Dean
2015-01-24 11:26 ` Eli Zaretskii
2015-01-24 10:30 ` Kelly Dean
2015-01-24 11:03 ` David Kastrup
2015-01-24 23:24 ` Kelly Dean
2015-01-25 9:16 ` David Kastrup
2015-01-26 3:52 ` Kelly Dean
2015-01-26 8:28 ` Thien-Thi Nguyen
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).