[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: replacing process sentinels and filters with hooks
Re: replacing process sentinels and filters with hooks
Wed, 3 Oct 2012 06:59:58 -0400
I think we are mostly on the same page now. When I say that "I don't
want to treat process callbacks specially" and "do we need a different
way of doing things?", I'm referring to the fact that add-function and
add-hook do similar things and it would be ideal (in my opinion) to
not have two general purpose APIs that (almost?) do the same thing.
I'm not necessarily calling for merging implementations, but if we end
up having both I think it would be nice to 1) point out the similarity
in the documentation and 2) have clear recommendations on which API to
use given the circumstances. For instance, would add-hook be (very
lightly-)deprecated in favor of add-function, since add-function is
more general than hooks? Or do we recommend the use of add-function
only when the callbacks take arguments? Or recommend add-function only
when we expect callbacks to modify arguments?
> How do you expect add-hook to work. E.g. give an example would be an
> appropriate add-hook call to add a function on your process-callback?
Hooks could use an interface similar to defadvice to change their
arguments: (hook-set-arg <index> <value>) would modify the argument
being passed to the next hook. Assuming for brevity that the argument
to a process callback is simply a string representing process-input:
(defun my-callback (input)
(message "Saw input: %s" input)
(hook-set-arg 0 (concat "Seen: " input)))
;; process-callbacks defaults to current buffer's process
(add-hook (process-callbacks) 'my-callback)
Yes, there seems to be a bit of ugliness in this case with
process-callbacks needing to return a symbol. In this case, I just
think of a symbol as acting as a reference type in ML, so it doesn't
bother me too much I guess.
My personal preference would be for hook-set-arg, because we wouldn't
have two different APIs for callbacks that take arguments, one being
more powerful than the other. I can imagine having different APIs
might be a problem: consider the case where a library author doesn't
know about add-function so they use the hook API. A user complains
that they need the ability to modify the arguments passed to the next
hook, and now the library author has to switch APIs (breaks backward
compat) or support two different APIs (breaks maintainer's spirit).
But you probably know better than I on this one, so use your judgment :)
> Note that comint-input-filter-functions is a hook on process-send-string
> rather than on the process-filter, whereas comint-preoutput-filter-functions
> (which is the hook on the process-filter) does allow modifying the string
> passed to the next function on the hook.
Argh, I was thinking of comint-preoutput-filter-functions in my head.
Sorry for the confusion!
I've copied the rest of your message below, as it wasn't sent to the
list. My apologies if it was meant to be private.
On Mon, Oct 1, 2012 at 10:25 PM, Stefan Monnier
>> shell is lucky that comint doesn't use a sentinel, because it
>> sometimes steals the process sentinel to save the shell history on
> Agreed, which is why I suggest `add/remove-function' so that packages
> can share something like process-sentinel without having to fight over
> it, or even having to plan ahead.
>> Perhaps that's not such a big deal, because both modes are in the
>> Emacs tree, and we can just fix that.
> No, it is important.
>>> - provide a standard way to combine sentinels and filters, which is to
>>> run them in sequence (for sentinels, it might be a fine default, but
>>> for filters, it might be more useful for each filter to be able to
>>> affect the <string> passed to the next filter).
>> I'll add that this can be useful for any hook that takes arguments.
>> I think it is a bad idea to consider process callback functions special.
> I do not want to treat process callback functions specially.
>> If it is useful behavior to modify callback arguments, then let us be
>> consistent and give that ability to any type of callback, not just
> That's what I want out of add/remove-function. Maybe it can even be
> used on (symbol-function f) as a lightweight alternative to defadvice.
>>> I'm not sure the first is useful since in my experience sentinels and
>>> filters do different things anyway.
>> I personally think it is cleaner to have them together, but if others
>> disagree there is probably a reason for it :) This is not an essential
>> part of my proposal.
> I'm not dead-set against merging them, but unless it simplifies
> implementation, I don't see much benefit, so I'm leaning towards keeping
> the separation.
>>> (add-function (process-filter proc) #'toto)
>> Why have a different way of doing things?
> Different from what?
>> API. The slogan: "If you want have a callback, use the hook API."
> Oh, so you want to use add-hook instead of a new add-function?
> The problem with that is that add-hook is written specifically for
> symbols/variables and I don't see how to make it work for
> process-callbacks, unless process-callbacks returns a symbol (itself
> holding a list of function), which I think is not very elegant.
>> Since there is no way for filters and sentinels to guarantee order
>> (just like hooks) I think the best route is to just add the ability
>> for a hook to modify the arguments that are passed to the next hook.
> In add/remove/run-hook, this is determined by the kind of hook, i.e. how
> the hook is run (run-hooks vs run-hook-with-args vs
> run-hook-with-args-until-success with with-wrapper-hook).
> Indeed for a new add-function, the choice would be made in add-function
>> Although I am not too convinced that this is important,
>> comint-input-filter-functions doesn't do this.
> But comint-input-filter-functions is comint's hook for
> process-send-string, whereas comint-preoutput-filter-functions (the hook
> corresponding to the process-filter) does have the ability to modify the
> string passed to the next function.
>>> run-hooks takes symbols as arguments.
>> It was just an example, I am a busy person and I think I got the gist
>> of what I was saying across. But I'll add (off-topic) that there seems
>> to be no reason for run-hooks to take a symbol as an argument. The C
>> code just immediately dereferences it.
> It's slightly more complex than that (it dereferences it potentially
> twice: once for the buffer-local value and once for the global value),
> but the real problem comes in add/remove-hook where receiving a list is
> not good enough since that list can be nil in which case there's no
> updatable field on which to add/remove the function (hence the need for
> an additional indirection, such as making function-callbacks return
> a symbol).