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

[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



reply via email to

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