From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Drew Adams Newsgroups: gmane.emacs.devel Subject: Default value of variables named `*-function' [was: Change in files.el] Date: Tue, 31 Jan 2017 10:40:10 -0800 (PST) Message-ID: <82b4b3b7-ff61-42a7-b9fb-df3cc26a3f30@default> References: <83mvebzh0k.fsf@gnu.org> <83bmurz0y9.fsf@gnu.org> <8360kzyxor.fsf@gnu.org> <83ziibxg7j.fsf@gnu.org> <83y3xvxfbs.fsf@gnu.org> <83wpdfxe96.fsf@gnu.org> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Trace: blaine.gmane.org 1485888079 14621 195.159.176.226 (31 Jan 2017 18:41:19 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Tue, 31 Jan 2017 18:41:19 +0000 (UTC) To: Kaushal Modi , Stefan Monnier , emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Tue Jan 31 19:41:15 2017 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cYdMg-0003SL-Mb for ged-emacs-devel@m.gmane.org; Tue, 31 Jan 2017 19:41:14 +0100 Original-Received: from localhost ([::1]:40399 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cYdMh-0004jo-4v for ged-emacs-devel@m.gmane.org; Tue, 31 Jan 2017 13:41:15 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:59040) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cYdLr-0004hq-8x for emacs-devel@gnu.org; Tue, 31 Jan 2017 13:40:25 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cYdLn-0007W6-69 for emacs-devel@gnu.org; Tue, 31 Jan 2017 13:40:23 -0500 Original-Received: from aserp1040.oracle.com ([141.146.126.69]:49577) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cYdLm-0007UW-TB for emacs-devel@gnu.org; Tue, 31 Jan 2017 13:40:19 -0500 Original-Received: from userv0021.oracle.com (userv0021.oracle.com [156.151.31.71]) by aserp1040.oracle.com (Sentrion-MTA-4.3.2/Sentrion-MTA-4.3.2) with ESMTP id v0VIeEjc017956 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 31 Jan 2017 18:40:15 GMT Original-Received: from aserv0122.oracle.com (aserv0122.oracle.com [141.146.126.236]) by userv0021.oracle.com (8.14.4/8.14.4) with ESMTP id v0VIeDC3000800 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 31 Jan 2017 18:40:14 GMT Original-Received: from abhmp0011.oracle.com (abhmp0011.oracle.com [141.146.116.17]) by aserv0122.oracle.com (8.14.4/8.14.4) with ESMTP id v0VIeCkf009053; Tue, 31 Jan 2017 18:40:13 GMT In-Reply-To: X-Priority: 3 X-Mailer: Oracle Beehive Extensions for Outlook 2.0.1.9.1 (1003210) [OL 12.0.6753.5000 (x86)] X-Source-IP: userv0021.oracle.com [156.151.31.71] X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4.x-2.6.x [generic] [fuzzy] X-Received-From: 141.146.126.69 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:211810 Archived-At: > I would appreciate the consistency of variables named > with -function/-predicate suffixes to have a function > has a default value. Being able to use add-function on > just variables is very convenient (I use it to tweak > region-extract-function). The default values also serve > as good examples. My comment here is not about providing an implicit/automatic default value. (I doubt that that is needed or a good idea, but I could be wrong.) My comment is that the default value for a given variable whose value is intended to be a (single) function _should usually_ be function `ignore'. Not implicitly (see previous paragraph) but explicitly: (defvar foo-function 'ignore). TL;DR: Start `-function' vars out with value `ignore', possibly advised, so `remove-function' can get you back to a no-op. But please read on... If the default value needs to be a function that does something (which is common), then instead of using, as the default value, the function that provides the default behavior, use `ignore' as the default value AND advise it immediately with the function that provides the default behavior. Why? Because then you can use `remove-function' to get a no-op. You need not set or bind the variable to 'ignore' to do that; just repeated `remove-function' will get you to the no-op `ignore'. `remove-function' is analogous to setting a cons-valued=20 variable to its cdr. If `(cdr (last xs))' is not nil then xs is not a true list (it is dotted). Using `ignore' as the starting point for function advice is like=20 using () as the starting point (the last cdr) of a list. Function `ignore' is more or less to advice what () is to a list of functions - an identity element. Advising the function that is the value of a `*-function' variable gives you the possibility of, in effect, applying any number of functions. Using `:after-while' or `:before-until', for example, gives you much the same effect as you get with a normal or abnormal hook (as opposed to a `*-function' hook). But there is this big difference between a hook whose value is a list of functions (a la `add-hook') and a `*-function' variable whose value is a function that is advised with, say, `:after-while': With a hook that is a list of functions, you can remove them all using `remove-hook'. With an advised function, the value is always a function. You can of course change the value to `ignore', but you cannot, just using `remove-function', get to a no-op function. Unless, that is, the starting point (the default value) is `ignore'. Hence my suggestion: Start with `ignore', advising it immediately if some default behavior is called for. That lets users and code use just `add-function' and `remove-function' to get the effect they have with `add-hook' and `remove-hook': a (possibly empty) sequence of functions applied in order. I pointed this out in a parenthical remark in this post: http://lists.gnu.org/archive/html/emacs-devel/2016-10/msg00415.html (Note that one difference from a hook is that a hook does not privilege the first hook function in any way (or the last, depending on how you look at it). Removing advice is not equivalent to `remove-hook'. It never "empties the hook" completely - the function that was advised is still there after removal of all advice.) Here's a case in point: Variable `isearch-filter-predicate' has a function value or nil. This is legacy. Users and code can still bind it or set it to nil. But they cannot set it to a list of functions. IOW, it is basically a single-function variable (which would normally be named `*-function') - except for the ability to use nil instead. I have code that lets you (interactively) add to, remove from, etc. the behavior of `isearch-filter-predicate' on the fly. For more info, see https://www.emacswiki.org/emacs/DynamicIsearchFiltering. You can hit a key to change the current filter predicate in ways like these: C-z - Remove a predicate that you specify (default: last-added predicate). C-z & Add a predicate, AND-ing it as an `:after-while' filter. C-z % Add a predicate that requires search hits to match a regexp you provide. C-z || Add a predicate, OR-ing it as a `:before-until' filter. C-z |1 Replace the last-added filter by OR-ing it with another. C-z ~~ Complement the overall filter predicate. C-z ~1 Replace the last-added filter by its complement. C-z ! Set the overall filter predicate. C-z 0 Reset the overall filter predicate to its default value (`isearch-filter-visible'). C-z c Add a predicate that limits search between two columns that you specify. C-z @ Add a predicate that constrains searching within a=20 given distance of (near) another search pattern (you specify the distance and pattern). Since the default value of `isearch-filter-predicate' is not `ignore' but `isearch-filter-visible', you cannot just add and remove advice to get a no-op behavior or a behavior that is not a modification of `isearch-filter-visible'. Instead, you must set (or bind) `isearch-filter-predicate'. This is a defect, resulting from legacy: (1) using nil instead of `ignore' as the no-op filter and (2) using `isearch-filter-visible' instead of `ignore' as the default filter. It would be nice to be able to just add & remove advice, to control the behavior. But that always acts on function `isearch-filter-visible', not on `ignore'. Code should of course be _able_ to set or bind the variable value - no question about that. But things are more flexible if you can _also_ do pretty much anything to modify the behavior using just advice. If my suggestion were applied to the case of `isearch-filter-predicate' then (1) it would be renamed (e.g., to `isearch-filter-function'), and (2) its default value would be `ignore'. Now, because `isearch-filter-predicate' is legacy, (1) the variable renaming would need to deprecate (but continue to support) the old name, and (2) the variable value nil would need to continue to be supported. This is just an example, to try to get across the suggestion that (1) we use `ignore' as the (explicit, not automatic/implied) default value of variables named `*-function', and (2) for any such variable whose default behavior needs to be a no-op, we immediately (i.e., by default) advise it to provide that default behavior. That gives users & code two ways to change it to a no-op: (a) set the variable value to `ignore' or (b) remove all advice from the default function (`ignore'). In a way, this amounts to saying that what is said (correctly) in (elisp) `Advice combinators' about various kinds of advice being "comparable for single-function hooks to (add-hook..." is not also true for `remove-function' - unless the starting point is function `ignore'. Repeatedly applying `remove-hook' will eventually get you to (), but repeatedly applying `remove-function' will not get you to `ignore', unless... You might point out that if a user or code _does_ just set the value of such a variable to some other function than `ignore' then `remove-function' will _not_ get back to `ignore'. Clearly. The effect of setting or (with a little more work) binding can be had using just advice, but nothing prevents someone from not using advice to change the value. Dunno whether I was clear or I am missing something important. But WDOT?