From: "Andreas Röhler" <andreas.roehler@online.de>
To: emacs-devel@gnu.org
Cc: Drew Adams <drew.adams@oracle.co>
Subject: Re: Default value of variables named `*-function' [was: Change in files.el]
Date: Wed, 1 Feb 2017 09:35:25 +0100 [thread overview]
Message-ID: <8e6ec9e5-d1db-843b-fbe8-45ed21b3e13d@online.de> (raw)
In-Reply-To: <82b4b3b7-ff61-42a7-b9fb-df3cc26a3f30@default>
On 31.01.2017 19:40, Drew Adams wrote:
>> 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
> 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
> 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
> 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?
>
+1
OTOH wondering if not a simple customizable listing of
buffers-not-to-save/query would deliver all needed.
Reading doc-string of optional arg PRED -- isn't that already kind of
over-engineered?
next prev parent reply other threads:[~2017-02-01 8:35 UTC|newest]
Thread overview: 33+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-01-28 2:16 Change in files.el Richard Stallman
2017-01-28 2:46 ` Stefan Monnier
2017-01-28 9:10 ` Eli Zaretskii
2017-01-28 14:40 ` Stefan Monnier
2017-01-28 14:57 ` Eli Zaretskii
2017-01-28 15:31 ` Dmitry Gutov
2017-01-28 16:12 ` Eli Zaretskii
2017-01-28 15:40 ` Stefan Monnier
2017-01-28 16:08 ` Eli Zaretskii
2017-01-28 16:51 ` Stefan Monnier
2017-01-28 17:11 ` Eli Zaretskii
2017-01-28 17:22 ` Stefan Monnier
2017-01-28 17:30 ` Eli Zaretskii
2017-01-28 17:42 ` Stefan Monnier
2017-01-28 17:53 ` Eli Zaretskii
2017-01-29 18:59 ` John Wiegley
2017-01-30 3:57 ` Leo Liu
2017-01-30 15:58 ` John Wiegley
2017-01-31 4:19 ` Leo Liu
2017-01-31 14:01 ` John Wiegley
2017-01-31 14:46 ` Stefan Monnier
2017-01-31 16:21 ` Kaushal Modi
2017-01-31 18:40 ` Default value of variables named `*-function' [was: Change in files.el] Drew Adams
2017-02-01 8:35 ` Andreas Röhler [this message]
2017-01-28 18:41 ` Change in files.el Mark Oteiza
2017-01-28 19:37 ` Eli Zaretskii
2017-02-01 3:49 ` Mark Oteiza
2017-02-01 7:33 ` Clément Pit-Claudel
2017-02-01 12:56 ` Eli Zaretskii
2017-02-01 14:12 ` Kaushal Modi
2017-01-29 0:21 ` Richard Stallman
2017-02-04 9:18 ` Eli Zaretskii
2017-02-04 23:52 ` Richard Stallman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=8e6ec9e5-d1db-843b-fbe8-45ed21b3e13d@online.de \
--to=andreas.roehler@online.de \
--cc=drew.adams@oracle.co \
--cc=emacs-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.