From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Kelly Dean Newsgroups: gmane.emacs.devel Subject: Re: Why is Elisp's defvar weird? And is eval_sub broken? Date: Sat, 14 Feb 2015 07:35:58 +0000 Message-ID: References: NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Trace: ger.gmane.org 1423899463 14455 80.91.229.3 (14 Feb 2015 07:37:43 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sat, 14 Feb 2015 07:37:43 +0000 (UTC) Cc: emacs-devel@gnu.org To: Stefan Monnier Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sat Feb 14 08:37:33 2015 Return-path: Envelope-to: ged-emacs-devel@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 1YMXIC-00062M-O2 for ged-emacs-devel@m.gmane.org; Sat, 14 Feb 2015 08:37:32 +0100 Original-Received: from localhost ([::1]:59021 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YMXIB-0008Fp-W8 for ged-emacs-devel@m.gmane.org; Sat, 14 Feb 2015 02:37:31 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:54972) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YMXHy-0008FV-AW for emacs-devel@gnu.org; Sat, 14 Feb 2015 02:37:19 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YMXHu-00080f-8x for emacs-devel@gnu.org; Sat, 14 Feb 2015 02:37:18 -0500 Original-Received: from relay5-d.mail.gandi.net ([2001:4b98:c:538::197]:50171) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YMXHu-00080a-09 for emacs-devel@gnu.org; Sat, 14 Feb 2015 02:37:14 -0500 Original-Received: from mfilter26-d.gandi.net (mfilter26-d.gandi.net [217.70.178.154]) by relay5-d.mail.gandi.net (Postfix) with ESMTP id 1D9D341C067; Sat, 14 Feb 2015 08:37:13 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at mfilter26-d.gandi.net Original-Received: from relay5-d.mail.gandi.net ([217.70.183.197]) by mfilter26-d.gandi.net (mfilter26-d.gandi.net [10.0.15.180]) (amavisd-new, port 10024) with ESMTP id 6K+LT93eE7Tz; Sat, 14 Feb 2015 08:37:11 +0100 (CET) X-Originating-IP: 66.220.3.179 Original-Received: from localhost (gm179.geneticmail.com [66.220.3.179]) (Authenticated sender: kelly@prtime.org) by relay5-d.mail.gandi.net (Postfix) with ESMTPSA id C23AF41C054; Sat, 14 Feb 2015 08:37:08 +0100 (CET) In-Reply-To: X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2001:4b98:c:538::197 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:183041 Archived-At: Stefan Monnier wrote: > The declaration of the var as being dynamically-scoped (aka "special") > is *local* to the (rest of the) current scope (typically the current fi= le). > > This is indispensable so that one package can use a dynamically-bound > variable `foo' without breaking some other package that expects `foo' t= o > be lexically-bound. desktop.el doesn't use desktop-first-buffer, desktop-buffer-ok-count, and= desktop-buffer-fail-count as global variables. It only uses them as dyna= mic variables, for implicit arguments and return values of functions. I.e= . outside of a let-binding, it doesn't use the symbols (except in defvar,= just to avoid byte compiler warnings). For that case, what I had in mind was a dynamic-let special form, being t= he same as =C2=ABlet=C2=BB, except with the following case removed: if (!NILP (lexenv) && SYMBOLP (var) && !XSYMBOL (var)->declared_special && NILP (Fmemq (var, Vinternal_interpreter_environment))) lexenv =3D Fcons (Fcons (var, tem), lexenv); so it always just does specbind (var, tem). The byte compiler could flag = an error if you use dynamic-let on a symbol that's already used as a lexi= cal variable. This way, there's no need to use defvar on symbols such as = the desktop.el symbols above. So defvar can be reserved just for the symb= ols that really are special, i.e. the ones that are used as global variab= les and for which dynamic variables instead of lexical variables are crea= ted to shadow the globals when you let-bind the symbols using standard =C2= =ABlet=C2=BB (in any file). A declaration of free dynamic variables for a function could tell the byt= e compiler that those free variables aren't typos, since otherwise the by= te compiler would expect either the symbol to be declared special or a le= xical variable by that name to be in scope. Also have a lexical-let special form (replacing the old lexical-let macro= ), being the same as =C2=ABlet=C2=BB, except with case above replaced by: CHECK_SYMBOL (var); if (NILP (lexenv)) lexenv =3D Qt; lexenv =3D Fcons (Fcons (var, tem), lexenv); and have it never do specbind (var, tem). The byte compiler could give a = warning if you use lexical-let on a symbol that's declared special. Then = everybody could use this faster form in the cases where all the variables= being bound in the =C2=ABlet=C2=BB are supposed to be lexical. This also= has the advantage of ensuring that those variables _are_ bound lexically= even if you forgot that some of the symbols you're using were declared s= pecial, and the byte compiler can see your intent to use lexicals and war= n you about the specials, which helps catch bugs. Then you never need standard (and slow, and bug-prone) =C2=ABlet=C2=BB, e= xcept for compatibility with old code, and for the rare cases where you m= ight need it for some mind-bending macros. I would vote for =E2=8C=9Cdlet=E2=8C=9D and =E2=8C=9Cllet=E2=8C=9D as the= names, or at least =E2=8C=9Cdynlet=E2=8C=9D and =E2=8C=9Clexlet=E2=8C=9D= , since Elisp code is already too verbose. For both correctness and speed, have the standard llet (accessible to int= erpreted code) include the CHECK_SYMBOL (var) above, and have the standar= d dlet include a runtime check of shadowing a lexical. Have byte-compiled= code use a pair of optimized special forms, not accessible to interprete= d code, with those checks omitted, since they're done at compile time. > Normally, such conflicts should never happen > because all special vars should be named with a "package prefix", but > sadly, reality is different, so it was indispensable to make this > effect local, to allow lexical-binding code to work reliably. By using llet, the byte compiler will catch such conflicts, and your code= (interpreted or compiled) that uses it will work reliably despite the co= nflicts. This means defvar's weird behavior is no longer needed.