From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Daniel Colascione Newsgroups: gmane.emacs.devel Subject: Re: lexbind ready for merge Date: Tue, 29 Mar 2011 21:10:19 -0700 Message-ID: <4D92AD2B.40502@gmail.com> References: <4D926EA9.5080509@gmail.com> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Trace: dough.gmane.org 1301458240 15330 80.91.229.12 (30 Mar 2011 04:10:40 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Wed, 30 Mar 2011 04:10:40 +0000 (UTC) Cc: emacs-devel@gnu.org To: Stefan Monnier Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Wed Mar 30 06:10:35 2011 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1Q4mjp-0000PR-09 for ged-emacs-devel@m.gmane.org; Wed, 30 Mar 2011 06:10:34 +0200 Original-Received: from localhost ([127.0.0.1]:44232 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Q4mjo-0003Al-9n for ged-emacs-devel@m.gmane.org; Wed, 30 Mar 2011 00:10:32 -0400 Original-Received: from [140.186.70.92] (port=46910 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Q4mji-0003Af-Od for emacs-devel@gnu.org; Wed, 30 Mar 2011 00:10:28 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Q4mjh-0005pB-CD for emacs-devel@gnu.org; Wed, 30 Mar 2011 00:10:26 -0400 Original-Received: from mail-pv0-f169.google.com ([74.125.83.169]:52055) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Q4mjh-0005p6-1h for emacs-devel@gnu.org; Wed, 30 Mar 2011 00:10:25 -0400 Original-Received: by pvg4 with SMTP id 4so191067pvg.0 for ; Tue, 29 Mar 2011 21:10:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:message-id:date:from:user-agent:mime-version:to :cc:subject:references:in-reply-to:content-type :content-transfer-encoding; bh=iQNCFZkAdhtafsDYxvSgDjfIn6sq1el5lASO6jLwTEE=; b=AW4LJs+Q5EILjpo66vgpXgjAtVnNVPSMy7AwdT1+i43dkEReQDlmN4YFw7O7ShkiM0 rleD/YQYthbR770NcMz90Sf0GVqbMClIj2pCia0p3qy+G2eQGMraoLSPHjhSKnQydBie HIP1t3kmG1XSr2M3NZ9uG/aVPE7dAqzOa+EVE= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=message-id:date:from:user-agent:mime-version:to:cc:subject :references:in-reply-to:content-type:content-transfer-encoding; b=p1QMdxpJTNasrAhdnwiZCqI8RfPwKPK3SjtuzEfo/AmYG2hHABJjffWWo0XjEkUST8 Q9OXCKdBKMdmIAvwcnnmpIUYcDpIoYtuAPjFGflvL6RHNchG05zTd3G2AXGgKaH7+Mbh JRKO8hKIH4qAarDdZIyn/q7pfUhuIupINtobQ= Original-Received: by 10.142.218.8 with SMTP id q8mr541601wfg.118.1301458223837; Tue, 29 Mar 2011 21:10:23 -0700 (PDT) Original-Received: from [0.0.0.0] (c-67-183-23-114.hsd1.wa.comcast.net [67.183.23.114]) by mx.google.com with ESMTPS id p40sm8125679wfc.17.2011.03.29.21.10.21 (version=SSLv3 cipher=OTHER); Tue, 29 Mar 2011 21:10:22 -0700 (PDT) User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2.15) Gecko/20110303 Thunderbird/3.1.9 In-Reply-To: X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 74.125.83.169 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.devel:137889 Archived-At: On 3/29/2011 6:22 PM, Stefan Monnier wrote: >> - apply-partially should have a compiler-macro now that we can implement it >> very efficiently; also, funcall-partially. > > The current definition of apply-partially is not too > inefficient, actually. I don't know what funcall-partially would > be like. And I don't like either of them: apply-partially is just a way > to make it easy to build closures by hand without resorting to > lexical-let and independently from lexical-binding, but once you use > lexical-binding you're usually better off using a plain closure. apply-partially at least involves less typing lexical-let, which (as I explain below) is required in some cases even with lexbind. As for funcall-partially: I never really liked how apply-partially differs from apply. The latter treats its last argument specially, while the former does not. If I had my way, I'd rename the current apply-partially to funcall-partially (or partial-funcall?) and create a new apply-partially that unpacks its last argument. But it probably can't be changed now... >> - It might be a good idea to remove the "Once Emacs 19 becomes standard..." >> comment from cl.el > > Feel free to do that on the trunk, I don't think it's really related > to lexbind. If I could, I would. :-) >> - Can lexical-let and lexical-let* be made a no-op when compiling lexbound >> code? Looking at cl.el, it appears they're still up their usual >> dirty tricks. > > They can *almost* be turned into `let' and `let*', except that > (lexical-let ((buffer-file-name 3)) ...) will bind buffer-file-name > lexically whereas `let' will always bind it dynamically. We could > either ignore those issues or try to handle them, but I'd rather just > mark lexical-let obsolete. I'd prefer to ignore the issues for now and transform lexical-let to let when lexical-binding is on, generating a compiler error if we're trying to lexically bind a special variable. I don't think many people try to do that. A macro that uses a lexical binding in its generated code still needs to use lexical-let in order for its generated form to work properly in either environment, and even outside macros, making lexical-let cheap in the lexbound case gives us a way to create backward-compatible code that automatically becomes more efficient in Emacs 24. > (Of course, there's also the difficulty for the macro to reliably > determine whether the expansion will be run in lexical-binding or > dynamic-binding mode). Wouldn't inspecting the value of lexical-binding work well enough? For evaluated code, the macro (regardless of how or whether it was compiled) will be called directly from the evaluator with the appropriate value of lexical-binding set. For compiled code, the macro will be called by the compiler with lexical-binding set to the value the compiler is using to compile the resulting form. The value of lexical-let at macro-run time and result-evaluation time *could* differ if the resulting form is squirreled away somewhere and reused later --- but I can't think of a case where that happens without the code being wrapped in some kind of function object that would capture the current value of lexical-let. Of course, you can lie: (defmacro* with-broken-code (&body body) (let (lexical-binding) (macroexpand-all `(progn ,@body))) That kind of thing is firmly in "It hurts when I do this" territory though. > >> - lexical-binding only applies to code evaluated by `eval-buffer' and >> eval-region'?! So I can't make code evaluated by M-: lexbound? > > ?!? AFAIK, M-: uses lexical or dynamic scoping according to the value > of lexical-binding in the current buffer. It does, but the documentation string still gives me the impression that it wouldn't be. Why isn't lexical-binding respected for all evaluation? >> - It'd be nice to be able to write small pieces of lexical code in >> non-lexbound code, e.g., in the expansion of a macro that gets used by both >> lexbound and non-lexbound. > > Yes, it'd be nice. > >> What's the best way to do that? > > Currently, I think the best way to do that is to add the feature to the > byte-compiler. The most promising avenue for it might be to use code > of the form ((closure () )) and > compile efficiently (I think currently such code will either result in > a complaint about a malformed function, or else will leave the function > uncompiled). Ah, I see what you mean. Would a with-lexical-scope form suffice? ;; with-lexical-scope is itself compiled with lexical-binding t (defmacro* with-lexical-scope (&body body) (let* ((vars (remove-if (lambda (var) (or (special-variable-p var) (not (boundp var)))) (find-free-vars `(progn ,@body)))) (closure `(closure (t) ; no environment ,@args ,@body))) `(funcall ,closure ,@vars))) (defvar b 42) (defun some-dynamic-function (a) (with-lexical-scope (lambda (c) (+ a b c))) ;; or even (with-lexical-scope (defun foo (arg) ...)) That's not the same as (defun foo (arg) (with-lexical-scope ...))) because the argument binding strategies differ. >> - The documentation claims that defun doesn't capture its lexical scope. In >> interpreted code, it does. > >> (require 'cl) >> (let ((bar2 5)) >> (defun foo () >> (incf bar2) >> (message "hi: %s" bar2))) > >> In compiled code, we do not capture the variable and instead warn about it. >> Instead, we should capture the variable. > > Yup. > >> Common Lisp explicitly allows this use, and it's convenient in >> some cases. > > If you need it you can use > > (let ((bar2 5)) > (defalias 'foo (lambda () > "Foo." > (incf bar2) > (message "hi: %s" bar2)))) > > IIRC, the reason why defun doesn't work for it is fundamentally linked > to some silly technicality, but I justify it for myself by the fact that > all the "defun within a non-empty context" I've seen were bogus, so I'm > not strongly motivated to handle it right. Even if it's not particularly common, being consistent with Common Lisp and having fewer special cases are good things. Some people use constructs like this to create module-private variables (which is a bad idea, but that doesn't stop people doing it.) >> - Disassembling a closure reports closed-over variables as constants; >> they're not. > > They are. Err, yes. They are. >> - Do we really use a whole cons cell for each closed-over variable, even in >> compiled code? > > Yes, tho only for variables which are mutated (yup, `setq' is costly). Couldn't we create a box type, which would would be like a cons except that it'd hold just one value? (The # read-syntax is available.)