From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: pjb@informatimago.com (Pascal J. Bourguignon) Newsgroups: gmane.emacs.help Subject: Re: 'Compiler' functionality for Emacs Lisp Date: Thu, 29 Jul 2010 09:55:00 +0200 Organization: Informatimago Message-ID: <87bp9qiuy3.fsf@kuiper.lan.informatimago.com> References: <87hbjjgdbd.fsf@decebal.nl> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: dough.gmane.org 1291854440 23131 80.91.229.12 (9 Dec 2010 00:27:20 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Thu, 9 Dec 2010 00:27:20 +0000 (UTC) To: help-gnu-emacs@gnu.org Original-X-From: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Thu Dec 09 01:27:16 2010 Return-path: Envelope-to: geh-help-gnu-emacs@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 1PQULq-0003xN-Fj for geh-help-gnu-emacs@m.gmane.org; Thu, 09 Dec 2010 01:27:14 +0100 Original-Received: from localhost ([127.0.0.1]:35930 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1PQULp-0006CS-LE for geh-help-gnu-emacs@m.gmane.org; Wed, 08 Dec 2010 19:27:13 -0500 Original-Path: usenet.stanford.edu!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail Original-Newsgroups: gnu.emacs.help Original-Lines: 157 Original-X-Trace: individual.net SyN909PzBgoULSvZqmVJTgCR8vc7tfqCt+RPhyh9NJzG/NCjZA Cancel-Lock: sha1:YTU1ZmQ2MTA0NDgwZDk5MDAwYjdjN2I2YzMyZjYxYmFjNGE2ZGNkMA== sha1:VgcjmDVtNod+dIX5hgcHpC5r4VM= Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAQMAAABtzGvEAAAABlBMVEUAAAD///+l2Z/dAAAA oElEQVR4nK3OsRHCMAwF0O8YQufUNIQRGIAja9CxSA55AxZgFO4coMgYrEDDQZWPIlNAjwq9 033pbOBPtbXuB6PKNBn5gZkhGa86Z4x2wE67O+06WxGD/HCOGR0deY3f9Ijwwt7rNGNf6Oac l/GuZTF1wFGKiYYHKSFAkjIo1b6sCYS1sVmFhhhahKQssRjRT90ITWUk6vvK3RsPGs+M1RuR mV+hO/VvFAAAAABJRU5ErkJggg== X-Accept-Language: fr, es, en X-Disabled: X-No-Archive: no User-Agent: Gnus/5.101 (Gnus v5.10.10) Emacs/23.2 (gnu/linux) Original-Xref: usenet.stanford.edu gnu.emacs.help:180170 X-BeenThere: help-gnu-emacs@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Users list for the GNU Emacs text editor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Errors-To: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.help:76295 Archived-At: Cecil Westerhof writes: > When using for example C++ the compiler does a lot of checks for you. > For example it checks if all your variables are declared or used and > it does even find potential memory leaks. Is there something like this > for Emacs Lisp? I am writing bigger functions nowadays. Yesterday I > found out that not all my variables where declared in a let block and > I had forgotten to remove a few I where not using anymore. Is there > something that could do these checks for me? Lisp is fundamentally different from C++. Perhaps you haven't noticed, but when you compile your lisp function, you don't have to recompile the whole emacs! This is something you would have to do with C++, to allow these global checks. About variables, again, emacs lisp variables are totally different from C++ variables. In C++, variables are lexical variables. In emacs lisp, all the variables are dynamic variables. This means that it is not an error to use a free variable in a function, or to define (with let) a variable that doesn't seem to be used in the let body. Because the variable may be defined in a different function that calls yours, or used in a different function that you call. (defun f () (let ((x 1)) ;; isn't x used? (g))) (defun g () (let ((y 2)) ;; isn't y used? (list x ; x is used here! (h)))) (defun h () y) ; y is used here! (f) ;; --> (1 2) Of course, it's up to the caller to fulfil the contract of function such as h, and to define their free variables: (h) ;; --> Debugger entered--Lisp error: (void-variable y) (let ((y 42)) (h)) ;; --> 42 Now, even more: (defun hh () (list y x)) ; yet other free variables. (defvar *hook* 'h) (defun g () (let ((y 2)) (message "ghh %S" *hook*) (list x (funcall *hook*)))) (f) ;; --> (1 2) (require 'cl) (setf *hook* 'hh) (f) ;; --> (1 (2 1)) which show that when this new g calls the function in *hook*, nobody can know in advance what function will be called. The emacs user may at any time change the value of the variable *hook*, to call another function. Therefore there is absolutely no way to do a comprenhesive and general compilation-time check of the use of emacs lisp variables. You're in a dynamic world! Anything can change at any time! Now, if you want (as we all should in most cases, really) to use a sublanguage where variables are used as if they were lexical variables, you can easily enough write static analysis tools for emacs lisp code. For example, here is a function that extracts the free variables from a lambda expression: (require 'cl) (defun* free-variables (expression &optional (bound-variables '())) (cond ((symbolp expression) (if (member expression bound-variables) '() (list expression))) ((atom expression) '()) ((eq 'lambda (car expression)) (let ((bound-variables (append (cadr expression) bound-variables))) (mapcan (lambda (subexpr) (free-variables subexpr bound-variables)) (cddr expression)))) (t (mapcan (lambda (subexpr) (free-variables subexpr bound-variables)) expression)))) (free-variables '((lambda (b) (+ ((lambda (x) (* 2 x)) a) b)) 3) '()) ;; --> (+ * a) (free-variables '(lambda () a) '()) ;; --> (a) Of course, you would have to process let, let*, macros, etc, etc, to make it complete. Other functions like this may be written to check that all variables are used in their lexical scope, and you may also check that any variable defined in a function f, that are visible in the scope of the call to a function g, are not free variables in the function g (or any function called from g). If you ever see f calling a hook, for which you cannot determine the set of functions that may be called at run-time, then you would have to further check that the variables of f are not free variables in all the functions in emacs lisp. Well, apart from the cases where you do want to use a special variable. For example, case-fold-search is a dynamic variable that is used by some emacs lisp functions as a global parameter: (defun f (cf) (let ((case-fold-search cf)) (string-match "abc" "toto ABC abc toto"))) (list (f nil) (f t)) ;; --> (9 5) In Common Lisp, we would use a declaration to indicate that we want a special variable (dynamic) instead of a normal variable (lexical): #+common-lisp (defun f (cf) (let ((case-fold-search cf)) (declare (special case-fold-search)) (do-something))) Of course, in Common Lisp since the default is lexical variables, the compiler may check more easily when you're using a free variable, or when you're not using a defined variable. Perhaps you may want to use emacs-cl, which is a Common Lisp implementation written in emacs-lisp, and which would allow you to write your emacs functions in Common Lisp instead of emacs lisp? -- __Pascal Bourguignon__ http://www.informatimago.com/