From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Nicolas Richard Newsgroups: gmane.emacs.help Subject: Re: Timer variable binding Date: Tue, 07 Jan 2014 17:15:16 +0100 Message-ID: <87d2k3ydij.fsf@yahoo.fr> References: NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: ger.gmane.org 1389112597 30086 80.91.229.3 (7 Jan 2014 16:36:37 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Tue, 7 Jan 2014 16:36:37 +0000 (UTC) Cc: help-gnu-emacs@gnu.org To: Johan Andersson Original-X-From: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Tue Jan 07 17:36:43 2014 Return-path: Envelope-to: geh-help-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1W0Zdv-0000TA-DU for geh-help-gnu-emacs@m.gmane.org; Tue, 07 Jan 2014 17:36:39 +0100 Original-Received: from localhost ([::1]:41480 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1W0ZIy-000553-9J for geh-help-gnu-emacs@m.gmane.org; Tue, 07 Jan 2014 11:15:00 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:55882) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1W0ZIZ-0004to-81 for help-gnu-emacs@gnu.org; Tue, 07 Jan 2014 11:14:42 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1W0ZIQ-0002kP-NG for help-gnu-emacs@gnu.org; Tue, 07 Jan 2014 11:14:35 -0500 Original-Received: from mxin.ulb.ac.be ([164.15.128.112]:59417) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1W0ZIQ-0002k8-Gc for help-gnu-emacs@gnu.org; Tue, 07 Jan 2014 11:14:26 -0500 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AqkEAKomzFKkD4Nx/2dsb2JhbABZuXmEAoEpdIIlAQEBAwF5BQsIAyElDwEEDTwTh28BAwkIqmaUFgFKDYRkF4d0hH2CEweENwSWK4Fshi6GLIU7gy47gSwE Original-Received: from geodiff-mac3.ulb.ac.be (HELO geodiff-mac3) ([164.15.131.113]) by smtp.ulb.ac.be with ESMTP; 07 Jan 2014 17:14:25 +0100 In-Reply-To: (Johan Andersson's message of "Tue, 7 Jan 2014 15:53:25 +0100") User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3.50 (gnu/linux) X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 164.15.128.112 X-BeenThere: help-gnu-emacs@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Users list for the GNU Emacs text editor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Original-Sender: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.help:95296 Archived-At: Johan Andersson 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