From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED.blaine.gmane.org!not-for-mail From: "Basil L. Contovounesios" Newsgroups: gmane.emacs.devel Subject: Re: Predicate for true lists Date: Wed, 17 Apr 2019 18:56:40 +0100 Message-ID: <87tvew7bxj.fsf@tcd.ie> References: <87fu3vdjjk.fsf@tcd.ie> <87bmcqhhsf.fsf@tcd.ie> <87in6xgtpb.fsf@tcd.ie> <2af892df-26cb-60b2-4fd8-067fcb3d32e9@cs.ucla.edu> <87r2kh9uwx.fsf@tcd.ie> <83h8lcnbxb.fsf@gnu.org> <87sh4s9poo.fsf@tcd.ie> <87k1q49p0i.fsf@tcd.ie> <87efgbbq2p.fsf@tcd.ie> <87a7gz8hp2.fsf@tcd.ie> <875zrn9bum.fsf@tcd.ie> <835zrm7fow.fsf@gnu.org> <878swivtcr.fsf@gmail.com> <87r2aayln2.fsf@tcd.ie> <87lg0hyidf.fsf@tcd.ie> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: blaine.gmane.org; posting-host="blaine.gmane.org:195.159.176.226"; logging-data="213449"; mail-complaints-to="usenet@blaine.gmane.org" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux) Cc: Eli Zaretskii , Alex Branham , monnier@iro.umontreal.ca, emacs-devel@gnu.org To: Drew Adams Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Wed Apr 17 19:57:37 2019 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([209.51.188.17]) by blaine.gmane.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1hGooS-000tMS-J9 for ged-emacs-devel@m.gmane.org; Wed, 17 Apr 2019 19:57:36 +0200 Original-Received: from localhost ([127.0.0.1]:57487 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hGooR-0000jI-K8 for ged-emacs-devel@m.gmane.org; Wed, 17 Apr 2019 13:57:35 -0400 Original-Received: from eggs.gnu.org ([209.51.188.92]:45709) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hGooC-0000dy-OL for emacs-devel@gnu.org; Wed, 17 Apr 2019 13:57:29 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hGonx-0005Oa-4P for emacs-devel@gnu.org; Wed, 17 Apr 2019 13:57:18 -0400 Original-Received: from mail-ed1-x52b.google.com ([2a00:1450:4864:20::52b]:44268) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1hGonr-0004wJ-Ek for emacs-devel@gnu.org; Wed, 17 Apr 2019 13:57:03 -0400 Original-Received: by mail-ed1-x52b.google.com with SMTP id i13so11051760edf.11 for ; Wed, 17 Apr 2019 10:56:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tcd-ie.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:references:date:in-reply-to:message-id :user-agent:mime-version; bh=YDE3GdRR8hnxsE9ejZlgoV7TtNTE9dypHSyfXmsqFhU=; b=BFoNVBW9uZfP7RfoSgQa/Gie1P+fzMn0rs2kP9ytKc/1zngjhiTVuzw+sLC42Ypmnq Mex3rtvtE+BQcd+W+EGkkmD0/nIJtESUk0xbRUXQ97ZZ+fRICtaf0UrnVO3h1oMrwekr rEuno4YwSWRXDwHVn3oH9aPSDYF2BHY7IoPRKm/VoS5NcagpOqRTE2ClrNWjHQuPLQEh CzbkKsU0PfmIiEF0h4n416caQov3y1MG/9frua1Tvc9UQLHTvWFpUOtLR6Wf+9TOL+Jg qBP9cVQWTBVUGf1yqQutndlwUkMPyLzl46NTE5oFrCNGK/pwfk5V2NqRpcFi238sMweT b3GA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:references:date:in-reply-to :message-id:user-agent:mime-version; bh=YDE3GdRR8hnxsE9ejZlgoV7TtNTE9dypHSyfXmsqFhU=; b=Xrniy3JcbBorlqaVAtLgTWPneuuJTYk79pzqoVKH99HKza3Q90/LILaI0Vp70MbYnS UVMp1GuNfGuOLrV1kdHaqE0sxIOOji5H/KYrLMrRGCszUSFCdpj4j096/1rcLn7VCnPM uq+6WaypXZKm19oJLvBJPBxo23hwYj6xJ1wpAwEx6g1EtwNEZC7lNj0X+TYAyiSq2LHW IJqNqFEHU5dPY02tS12JJnQVFUis9Zs5TEG174vphoElR/r/vB9yAA5+BAttQmF57g53 nDQFDKB6abpfiDyck6nFYqrKFH0TY6W4lLK6uhN7VP9NrDQ5MkWdolbeF7B0JIeToX/I KGPQ== X-Gm-Message-State: APjAAAX5uPCwwcToJLQpUArjNuZlDmRGFU9lAcZt1bupIoXIpqVfXJfR yhnEhZs1Jkz7Bm+uUM0xpcN2fw== X-Google-Smtp-Source: APXvYqzrPP+hlFrsUekoLeBNvLl1hsG0PinKtoydEmaR/bNe02DSpxGSqmbWAwtMmWEm0vmXvteqHQ== X-Received: by 2002:a17:906:90d3:: with SMTP id v19mr17162382ejw.268.1555523809280; Wed, 17 Apr 2019 10:56:49 -0700 (PDT) Original-Received: from localhost ([86.43.102.231]) by smtp.gmail.com with ESMTPSA id t51sm2922479edb.30.2019.04.17.10.56.47 (version=TLS1_3 cipher=AEAD-AES256-GCM-SHA384 bits=256/256); Wed, 17 Apr 2019 10:56:47 -0700 (PDT) In-Reply-To: <87lg0hyidf.fsf@tcd.ie> (Basil L. Contovounesios's message of "Wed, 10 Apr 2019 16:45:00 +0100") X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::52b X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:235597 Archived-At: --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0001-Improve-pure-and-side-effect-free-docs.patch >From cc5646ae517f0792e5acd721f4f2f6dec7a602b3 Mon Sep 17 00:00:00 2001 From: "Basil L. Contovounesios" Date: Wed, 17 Apr 2019 16:34:47 +0100 Subject: [PATCH 1/2] Improve pure and side-effect-free docs For discussion, see thread starting at: https://lists.gnu.org/archive/html/emacs-devel/2019-04/msg00316.html * doc/lispref/customize.texi (Composite Types): Do not overspecify :match-alternatives predicates. * doc/lispref/functions.texi (What Is a Function): Define what a pure function is. * doc/lispref/internals.texi (Writing Emacs Primitives): Describe currently preferred approach to marking primitives as pure and side-effect-free. * doc/lispref/macros.texi (Eval During Expansion): Index under 'side effect'. * doc/lispref/symbols.texi (Standard Properties): Expand description of pure and side-effect-free properties. --- doc/lispref/customize.texi | 8 ++++---- doc/lispref/functions.texi | 5 +++++ doc/lispref/internals.texi | 14 ++++++++++---- doc/lispref/macros.texi | 1 + doc/lispref/symbols.texi | 15 +++++++++++---- 5 files changed, 31 insertions(+), 12 deletions(-) diff --git a/doc/lispref/customize.texi b/doc/lispref/customize.texi index f71dedfd8b..02eefe0f58 100644 --- a/doc/lispref/customize.texi +++ b/doc/lispref/customize.texi @@ -950,10 +950,10 @@ Composite Types @itemize @bullet @item -A predicate---that is, a function of one argument that has no side -effects, and returns either @code{nil} or non-@code{nil} according to -the argument. Using a predicate in the list says that objects for which -the predicate returns non-@code{nil} are acceptable. +A predicate---that is, a function of one argument that returns either +@code{nil} or non-@code{nil} according to the argument. Using a +predicate in the list says that objects for which the predicate +returns non-@code{nil} are acceptable. @item A quoted constant---that is, @code{'@var{object}}. This sort of element diff --git a/doc/lispref/functions.texi b/doc/lispref/functions.texi index 222f863c98..0f9c977268 100644 --- a/doc/lispref/functions.texi +++ b/doc/lispref/functions.texi @@ -38,11 +38,16 @@ What Is a Function @cindex return value @cindex value of function @cindex argument +@cindex side effect +@cindex pure function In a general sense, a function is a rule for carrying out a computation given input values called @dfn{arguments}. The result of the computation is called the @dfn{value} or @dfn{return value} of the function. The computation can also have side effects, such as lasting changes in the values of variables or the contents of data structures. +A @dfn{pure function} is a function which, in addition to having no +side effects, always returns the same value for the same combination +of arguments, regardless of external factors such as machine type. In most computer languages, every function has a name. But in Lisp, a function in the strictest sense has no name: it is an object which diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi index 8ebe47d9ad..9947e37ca1 100644 --- a/doc/lispref/internals.texi +++ b/doc/lispref/internals.texi @@ -1031,10 +1031,16 @@ Writing Emacs Primitives @file{lisp.h} contains the definitions for some important macros and functions. - If you define a function which is side-effect free, update the code -in @file{byte-opt.el} that binds @code{side-effect-free-fns} and -@code{side-effect-and-error-free-fns} so that the compiler optimizer -knows about it. +@cindex @code{side-effect-free} +@cindex @code{pure} +@vindex side-effect-free-fns +@vindex side-effect-and-error-free-fns + If you define a function which is side-effect free and/or pure, give +it a non-@code{nil} @code{side-effect-free} and/or @code{pure} +property, respectively (@pxref{Standard Properties}). Alternatively, +you can update the code in @file{byte-opt.el} that binds +@code{side-effect-free-fns} and @code{side-effect-and-error-free-fns}, +but this approach is less modular and no longer encouraged. @node Writing Dynamic Modules @section Writing Dynamically-Loaded Modules diff --git a/doc/lispref/macros.texi b/doc/lispref/macros.texi index a422ba9750..bcee5b1078 100644 --- a/doc/lispref/macros.texi +++ b/doc/lispref/macros.texi @@ -523,6 +523,7 @@ Eval During Expansion @node Repeated Expansion @subsection How Many Times is the Macro Expanded? +@cindex side effect Occasionally problems result from the fact that a macro call is expanded each time it is evaluated in an interpreted function, but is diff --git a/doc/lispref/symbols.texi b/doc/lispref/symbols.texi index a214a2d3fd..e49c500701 100644 --- a/doc/lispref/symbols.texi +++ b/doc/lispref/symbols.texi @@ -558,9 +558,12 @@ Standard Properties modes. @xref{Setting Hooks}. @item pure +@cindex @code{pure} If the value is non-@code{nil}, the named function is considered to be -side-effect free. Calls with constant arguments can be evaluated at -compile time. This may shift run time errors to compile time. +side-effect free and pure (@pxref{What Is a Function}). Calls with +constant arguments can be evaluated at compile time. This may shift +run time errors to compile time. Not to be confused with pure storage +(@pxref{Pure Storage}). @item risky-local-variable If the value is non-@code{nil}, the named variable is considered risky @@ -579,9 +582,13 @@ Standard Properties for the named variable. @xref{File Local Variables}. @item side-effect-free +@cindex @code{side-effect-free} A non-@code{nil} value indicates that the named function is free of -side-effects, for determining function safety (@pxref{Function -Safety}) as well as for byte compiler optimizations. Do not set it. +side effects (@pxref{What Is a Function}), so the byte compiler may +ignore calls whose value is unused. If the property's value is +@code{error-free}, the byte compiler may even delete such unused +calls. In addition to byte compiler optimizations, this property is +also used for determining function safety (@pxref{Function Safety}). @item variable-documentation If non-@code{nil}, this specifies the named variable's documentation -- 2.20.1 --=-=-= Content-Type: text/x-diff Content-Disposition: attachment; filename=0002-Move-side-effect-free-from-unsafep.el-to-subr.el.patch >From e0e72e306400fb129379d1af3a8fbd3fd643fa6c Mon Sep 17 00:00:00 2001 From: "Basil L. Contovounesios" Date: Wed, 17 Apr 2019 17:35:12 +0100 Subject: [PATCH 2/2] Move side-effect-free from unsafep.el to subr.el * lisp/emacs-lisp/unsafep.el: Move side-effect-free property setting from here... * lisp/subr.el: ...to here, as function declarations for modularity. --- lisp/emacs-lisp/unsafep.el | 5 ----- lisp/subr.el | 8 ++++++++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lisp/emacs-lisp/unsafep.el b/lisp/emacs-lisp/unsafep.el index d20b751d88..1a2f1f31b1 100644 --- a/lisp/emacs-lisp/unsafep.el +++ b/lisp/emacs-lisp/unsafep.el @@ -92,11 +92,6 @@ unsafep-vars in the parse.") (put 'unsafep-vars 'risky-local-variable t) -;;Side-effect-free functions from subr.el -(dolist (x '(assoc-default butlast last match-string - match-string-no-properties member-ignore-case remove remq)) - (put x 'side-effect-free t)) - ;;Other safe functions (dolist (x '(;;Special forms and catch if or prog1 prog2 progn while unwind-protect diff --git a/lisp/subr.el b/lisp/subr.el index bf3716bbd3..f68f9dd419 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -580,6 +580,7 @@ last If LIST is nil, return nil. If N is non-nil, return the Nth-to-last link of LIST. If N is bigger than the length of LIST, return LIST." + (declare (side-effect-free t)) (if n (and (>= n 0) (let ((m (safe-length list))) @@ -591,6 +592,7 @@ butlast "Return a copy of LIST with the last N elements removed. If N is omitted or nil, the last element is removed from the copy." + (declare (side-effect-free t)) (if (and n (<= n 0)) list (nbutlast (copy-sequence list) n))) @@ -726,6 +728,7 @@ assoc-default If no element matches, the value is nil. If TEST is omitted or nil, `equal' is used." + (declare (side-effect-free t)) (let (found (tail alist) value) (while (and tail (not found)) (let ((elt (car tail))) @@ -739,6 +742,7 @@ member-ignore-case ELT must be a string. Upper-case and lower-case letters are treated as equal. Unibyte strings are converted to multibyte for comparison. Non-strings in LIST are ignored." + (declare (side-effect-free t)) (while (and list (not (and (stringp (car list)) (eq t (compare-strings elt 0 nil (car list) 0 nil t))))) @@ -822,6 +826,7 @@ alist-get (defun remove (elt seq) "Return a copy of SEQ with all occurrences of ELT removed. SEQ must be a list, vector, or string. The comparison is done with `equal'." + (declare (side-effect-free t)) (if (nlistp seq) ;; If SEQ isn't a list, there's no need to copy SEQ because ;; `delete' will return a new object. @@ -832,6 +837,7 @@ remq "Return LIST with all occurrences of ELT removed. The comparison is done with `eq'. Contrary to `delq', this does not use side-effects, and the argument LIST is not modified." + (declare (side-effect-free t)) (while (and (eq elt (car list)) (setq list (cdr list)))) (if (memq elt list) (delq elt (copy-sequence list)) @@ -3898,6 +3904,7 @@ match-string STRING should be given if the last search was by `string-match' on STRING. If STRING is nil, the current buffer should be the same buffer the search/match was performed in." + (declare (side-effect-free t)) (if (match-beginning num) (if string (substring string (match-beginning num) (match-end num)) @@ -3911,6 +3918,7 @@ match-string-no-properties STRING should be given if the last search was by `string-match' on STRING. If STRING is nil, the current buffer should be the same buffer the search/match was performed in." + (declare (side-effect-free t)) (if (match-beginning num) (if string (substring-no-properties string (match-beginning num) -- 2.20.1 --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable "Basil L. Contovounesios" writes: >> Isn't this in direct contradiction with (info "(elisp) Standard >> Properties") which states that side-effect-free should not be set?: >> >> =E2=80=98side-effect-free=E2=80=99 >> A non-=E2=80=98nil=E2=80=99 value indicates that the named function= is free of >> side-effects, for determining function safety (*note Function >> Safety::) as well as for byte compiler optimizations. Do not set >> it. >=20 > No, because the audience of (info "(elisp) Standard Properties") is the > average Elisp author, whereas the audience of (info "(elisp) Writing > Emacs Primitives") is the average contributor to Emacs core. >=20 > Currently, the side-effect-free property seems to be intended as an > internal one, since it makes some pretty strong guarantees, and is > described only in the commentary and code of byte-opt.el. This is my > interpretation of the "Do not set it" wording. Upon further reading of byte-opt.el and byte-run.el and inspection of the history of this documentation, I see nothing internal about the side-effect-free property. In other words, this seems to be a near-identical case of bug#13823. > Unless someone beats me to it, I intend to try to clarify this in the > next version of my patch. I attach two patches. The first updates the Elisp manual as discussed, and the second moves all side-effect-free property setting from unsafep.el to subr.el, as declarations of the relevant functions. WDYT? Thanks, --=20 Basil --=-=-=--