[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Timer variable binding
From: |
Nicolas Richard |
Subject: |
Re: Timer variable binding |
Date: |
Tue, 07 Jan 2014 17:15:16 +0100 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/24.3.50 (gnu/linux) |
Johan Andersson <johan.rejeep@gmail.com> writes:
> I have some questions regarding timers.
To understand what's going on, you also need to understand what lexical
and dynamical binding is. See (info "(elisp) Variable Scoping")
> This code will start a timer and the first time the callback runs, the
> timer is canceled. Works great!
>
> (let ((timer (run-at-time 0 1 (lambda ()
> (cancel-timer timer))))))
>
> In the above example I can access the timer variable inside the function
> callback.
Just changing the name from "timer" to "foobar" will make it complain :
(let ((foobar (run-at-time 1 1 (lambda ()
(cancel-timer foobar))))))
In fact you are lucky (or not, depending on the point of view) to give
your variable a symbol (namely, "timer") that is dynamically bound to
the 'current timer' at the time the callback function is being run.
I guess it happens in the function "timer-event-handler" : the argument
of that function is named "timer", and it is dynamically bound because
that file does not use lexical binding -- if it did, it'd make an error
with "timer" as well as with "foobar".
> But in this code, I cannot access the variable my-var. Nothing is
> printed. In Emacs 24.3.1 I see no error, but in 24.3.50.1 I get
> (void-variable my-var). Why is there no error in 24.3.1?
I don't know.
> (let* (timer (my-var 10))
> (setq timer (run-at-time 0 1 (lambda ()
> (print my-var)
> (cancel-timer timer)))))
This now should make sense : in fact none of your "timer" or "my-var"
are seen by the callback. It's pure luck that "timer", when the lambda
is run, refers to the current timer.
Now if you run your code with lexical-binding set to 't'
(let* (timer (my-var 10))
(setq timer (run-at-time 0 1 (lambda ()
(print my-var)
(cancel-timer timer)))))
It'll work as expected: the lambda now is made into a closure (i.e. a
function which knows about its current lexical environment).
Then this will work :
(let* (timer (my-var 10))
(setq timer (run-at-time 0 1 (lambda nil
(setq my-var (1- my-var))
(message "my-var: %s" my-var)
(when (= my-var 0)
(cancel-timer timer))))))
but this won't work :
(let* (timer (my-var 10))
(setq timer (run-at-time 0 1 (lambda (my-var)
(setq my-var (1- my-var))
(message "my-var: %s" my-var)
(when (= my-var 0)
(cancel-timer timer)))
my-var)))
> Can someone please explain these weird behaviors?
I hope I did ; don't hesitate to ask further.
--
Nicolas