help-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Improve this snippet!


From: Miguel Guedes
Subject: Re: Improve this snippet!
Date: 23 Jun 2013 08:28:10 GMT
User-agent: Pan/0.139 (Sexual Chocolate; GIT bf56508 git://git.gnome.org/pan2)

On Sat, 22 Jun 2013 11:54:46 +0200, Pascal J. Bourguignon wrote:

> You could use:
> 
>              (ecase name
>                ((foo) (setf fn-foo (cdr i))) ((bar) (setf fn-foo (cdr
>                i))))
> 
> instead of cond. (ecase having the advantage over case to signal an
> error if the value is not amongst the cases.
> 
> But in your case, see below.
> 
> Otherwise, it looks good, in the context of emacs configuration.
> 
> One thing you may want to add, is a functional wrapper over fn-foo, etc.
> 
> The point is to wrap the binding of foo with a fbinding of foo
> funcalling or applying it.
> 
>        (defun foo (&rest args)
>           (apply foo args))
> 

Could you please elaborate a bit more on this?  Does a functional wrapper 
overcome some sort of issue I'm not aware of? 

> 
> Let's write a macro to do it nicely:
> 
> (require 'cl)
> 
> (defvar *hooked-functions* '() "List of hooked functions.")
> 
> (defmacro define-hooked-function (name default-function-name)
>    `(progn
>        (defvar ,name nil ,(format "The hook of function %s" name))
>        (setq ,name ,default-function-name)
>        (defun ,name (&rest args)
>           (apply ,name args))
>        (pushnew ',name *hooked-functions*)
>        ',name))
> 
> (defun remove-hooked-function (name)
>    (setf *hooked-functions* (remove name *hooked-functions*))
>    name)
> 
> 
> (defun hooked-function-p (name)
>    (not (not (member name *hooked-functions*))))
> 
> (defun set-function-hook (hooked-function-name meat-function-name)
>    (if (hooked-function-p hooked-function-name)
>       (set hooked-function-name meat-function-name)
>       (error "%s is not a hooked function." hooked-function-name)))
> 
> (defun call-hooked-function (name &rest arguments)
>    (apply name arguments))
> 
> 
> 
> (defun default-foo (x) (message "default foo %s" x))
> (define-hooked-function foo 'default-foo)
> 
> (foo 42)                       --> "default foo 42"
> (hooked-function-p 'foo)       --> t
> 
> (set-function-hook 'foo (lambda (z) (format "anonymous meat %s" z)))
> 
> (foo 42)                       --> "anonymous meat 42"
> (call-hooked-function 'foo 42) --> "anonymous meat 42"
> 
> 
> So your code becomes:
> 
> (define-hooked-function foo 'default-foo)
> (define-hooked-function bar 'default-bar)
> 
> (let ((mode-descriptor
>        '("c++-mode"
>          ((foo . specific-c++-mode-implementation-foo)))))
>   (loop for (name . meat) in (second mode-descriptor)
>         do (set-function-hook name meat)))
> 
> 
> Once you'd have fun with doing it yourself like that, you can realize
> that you have a little problem: if we later use defun on foo, it will
> still be on the *hooked-functions* list, so we could still  use
> set-function-hook on it, but without further effect (unless the defun
> calls the function bound to the foo variable).
> 

That is an important point you raise though later use of defun on hooked 
functions would never happen in the minor mode I'm writing.

Have to say this is a very interesting and nicely structured way of doing 
it!

> 
> The solution would be to ignore all this, and just use the defalias
> function:
> 
> 
> (defalias 'foo 'default-foo)
> (defalias 'bar 'default-bar)
> 
> (foo 42) --> "default foo 42"
> 
> (defun specific-c++-mode-implementation-foo (z)
>    (message "specific-c++-mode-implementation-foo %s" z))
> 
> (let ((mode-descriptor
>        '("c++-mode"
>          ((foo . specific-c++-mode-implementation-foo)))))
>   (loop for (name . meat) in (second mode-descriptor)
>         do (defalias name meat)))
> 
> (foo 42) --> "specific-c++-mode-implementation-foo 42"

The defalias option does look attractively simple and effective but 
unfortunately the hooked functions must all be buffer local because not 
all buffers will share the same major mode.

Pascal, thank you very much for such a comprehensive reply; I've learnt 
(and hopefully others) quite a bit from your code and approaches!


-- 
Miguel


reply via email to

[Prev in Thread] Current Thread [Next in Thread]