unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* CL package serious deficiencies
@ 2012-02-06 14:18 egnarts-ms
  2012-02-06 21:08 ` Stefan Monnier
  0 siblings, 1 reply; 104+ messages in thread
From: egnarts-ms @ 2012-02-06 14:18 UTC (permalink / raw)
  To: Emacs-devel


Hello to everyone ! In this message I would like to share my (mostly
negative) experience with CL package of Elisp.  I'm sure, some Emacs/Elisp
gurus are already familiar with many of these, but I still believe I have to
say something new.  Let's start.

1. The most striking thing is the way symbol macros are implemented: authors
of CL merely put cons cells ("symbol-name" <expansion>) onto
`cl-macro-environment' variable, and when the time of possible
macroexpansion comes, this alist is searched with assq -- that it, strings
are compared with `eq'.
  This obviously is not correct. Look at this example:

(defmacro test-macro ()
  (let* ((symbol-1 'sym)
	 (symbol-2 (make-symbol (symbol-name symbol-1))))
    `(let ((v1 0)
	   (v2 0))
       (symbol-macrolet ((,symbol-1 (incf v1))
			          (,symbol-2 (incf v2)))
	 ,symbol-1
	 ,symbol-2
	 (list v1 v2)))))

(princ (test-macro))

This code prints (0 2), when it should print (1 1): that's because the same
string object serves the purpose of being the symbol name for 2 distinct
symbols. This situation is only possible if we deal with uninterned symbols
(and in more-or-less serious Lisp programming this practice is quite
common).

I tested this exampe (as well as all the following ones) in CLISP 2.41.1; it
prints (1 1).


2. Generalized variables.

`get-setf-method' works by calling `macroexpand' when it cannot find a
setf-method for a form.  `macroexpand' honestly expands this form the whole
way down, without regarding to all the intermediate forms; 
http://www.lispworks.com/documentation/HyperSpec/Body/05_abg.htm Common Lisp
uses  `macroexpand-1' for the same purpose.  This means that in case of any
intermediate macroexpansion result having a setf-method defined, it will be
ignored.  Only the end non-macro-call form is considered for setf-method.

I cannot give right away a good example of a harm this may cause. 
Nevertheless, this behavior seems fishy.. for instance, defining
setf-methods for macro names may lead to counterintuitive things: imagine
there is some other macro named B that expands into the call of this macro
(named, say, A), and A expands into a non-macro form X (for instance, just
car of smth).  Given that B has no setf-method defined, when
`get-setf-method' searches for the setf-method for B, the setf-method for A
doesn't count at all: it is just skipped.  X is what is searched in this
case.

`macroexpand-1' is absent in Emacs Lisp.


3. The way `get-setf-method', `incf', `decf', `push', `pushnew' and `pop'
deal with symbol macros.
Look at this:
(defun get-setf-method (place &optional env)
  (if (symbolp place)
      (let ((temp (make-symbol "--cl-setf--")))
	(list nil nil (list temp) (list 'setq place temp) place))
    ...

`get-setf-method' is absolutely ignorant of symbol macros: the fact that
"place" satisfies "symbolp" doesn't in any way mean it is a simple variable,
since we have a concept of symbol macro in the language.  The same thing is
true about all 5 functions listed above. 

To see a real example, consider the following:

(cl-macroexpand-all
 '(symbol-macrolet ((s (cadr (get-some-list))))
    (incf s)))

which results in

(let* ((--cl-x-- (get-some-list)))
  (setcar (cdr --cl-x--)
             (1+ (cadr (get-some-list)))))

this calls "get-some-list" 2 times, which is apparently erroneous.  Again,
Common Lisp makes only 1 call.

4. `cl-macroexpand-all'. This should be blamed for 2 things.

First, it doesn't macroexpand all, in contrast to what its name states.  Try
out this:

(cl-macroexpand-all
 '(let (((car x) 10))
    (body-1)))

You get the following result:

(letf (((car x) 10)) (body-1)),

and this is not the result of the macroexpansion ! Yes, I agree that this
case is unlikely: `let' is not supposed to bind places, this feature was
supposed to be internal to CL implementation.. but wait, this function is
nevertheless cheating.  It doesn't do what it must; it reckons upon someone
else to finish the job.  In some advanced, sophisticated code this hidden
flaw may suddenly show itself.

Second, look at the following code:

((eq (car form) 'setq)
 (let* ((args (cl-macroexpand-body (cdr form) env)) (p args))
   (while (and p (symbolp (car p))) (setq p (cddr p)))
   (if p (cl-macroexpand-all (cons 'setf args)) (cons 'setq args))))

This is actually a cond clause from `cl-macroexpand-all'.  See, it looks
whether any of "setq" targets in not a simple symbol, and if it's not, we
end up with a "setf" form being processed instead of original "setq" form. 
We have already discussed that problem: full expansion of "setq" arguments. 
No intermediate setf-methods have a chance to come up and be considered.

5. Loop facility, if/when/unless clause.  This is the most violent point of
all above.

To put it short, in the loop clause that follows "if" we can access the
result of evaluation of the condition with the name "it".  But have a look
at how they have implemented that "it":

(setq form (list* 'if (list 'setq temp cond)
		       (subst temp 'it form)))

Just subst, and that's all.  There's no surprise that when I put my
anaphoric "awhen" construct (inspired by Paul Graham) inside the clause
following "when" in a loop, I got something uncompilable.


Conclusion
I can draw the only conclusion from all above: Elisp has not been used much
to create true Lispy programs.  Features like symbol macros and generalized
variables were introduced to be quite close to those respective concepts of
Common Lisp, but they are still not that mature.

I've managed to fix all above (except `pop', `push', `incf'.. -- they proved
hard to be changed and recompiled correctly), and I'm still using Emacs, and
I'm still programming in Elisp.  I'm sure Elisp does his job of being an
excellent training ground for learning Lisp concepts.
-- 
View this message in context: http://old.nabble.com/CL-package-serious-deficiencies-tp33271707p33271707.html
Sent from the Emacs - Dev mailing list archive at Nabble.com.




^ permalink raw reply	[flat|nested] 104+ messages in thread

end of thread, other threads:[~2012-02-19 12:52 UTC | newest]

Thread overview: 104+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-02-06 14:18 CL package serious deficiencies egnarts-ms
2012-02-06 21:08 ` Stefan Monnier
2012-02-06 21:53   ` Drew Adams
2012-02-07  3:02     ` Stefan Monnier
2012-02-07 12:04       ` egnarts-ms
2012-02-07 17:36         ` Stefan Monnier
2012-02-08 13:15           ` egnarts-ms
2012-02-08 19:07             ` Stefan Monnier
2012-02-07 12:29     ` egnarts-ms
2012-02-07 18:43     ` Nix
2012-02-07 19:11       ` Lennart Borgman
2012-02-07 19:15         ` Juanma Barranquero
2012-02-07 20:54           ` Lennart Borgman
2012-02-07 21:03         ` John Wiegley
2012-02-07 21:06         ` Nix
2012-02-07 21:08           ` Lennart Borgman
2012-02-07 21:10             ` Nix
2012-02-07 21:12               ` Lennart Borgman
2012-02-07 21:23                 ` Nix
2012-02-07 21:29                   ` Lennart Borgman
2012-02-07 21:30                     ` Nix
2012-02-07 21:32                   ` Glenn Morris
2012-02-07 21:34                   ` Daniel Colascione
2012-02-07 21:42                     ` Tom Tromey
2012-02-08  1:53                       ` Leo
2012-02-07 22:16                     ` Alan Mackenzie
2012-02-07 22:19                       ` Nix
2012-02-08 13:28                     ` Richard Stallman
2012-02-08 15:00                       ` Tom Tromey
2012-02-09  6:29                         ` Richard Stallman
2012-02-09 14:23                           ` Eric Schulte
2012-02-10 15:44                             ` Richard Stallman
2012-02-10 18:36                               ` Tom Tromey
2012-02-10 15:52                             ` Tom Tromey
2012-02-10 16:23                               ` Drew Adams
2012-02-10 16:42                               ` Ted Zlatanov
2012-02-09  6:30                         ` Richard Stallman
2012-02-09 13:56                           ` Ted Zlatanov
2012-02-10 15:44                             ` Richard Stallman
2012-02-10 18:34                               ` Tom Tromey
2012-02-10 15:48                           ` Tom Tromey
2012-02-10 18:29                             ` Stefan Monnier
2012-02-08  2:07                   ` Stephen J. Turnbull
2012-02-07 22:41               ` Glenn Morris
2012-02-07 23:10                 ` Nix
2012-02-08 13:42                   ` Eric Schulte
2012-02-08 13:46                     ` Lennart Borgman
2012-02-08 13:51                       ` Eric Schulte
2012-02-08 15:29                         ` Lennart Borgman
2012-02-08 15:39                           ` Eric Schulte
2012-02-08 15:43                             ` Lennart Borgman
2012-02-08 14:26                     ` Drew Adams
2012-02-08 13:15         ` Teemu Likonen
2012-02-09  7:33           ` spam- or registry-related things in Gnus need cl at run-time? (was: CL package serious deficiencies) Reiner Steib
2012-02-09 16:39             ` spam- or registry-related things in Gnus need cl at run-time? Teemu Likonen
2012-02-07 23:48       ` CL package serious deficiencies Stefan Monnier
2012-02-07 23:52         ` Nix
2012-02-08  0:10           ` Lennart Borgman
2012-02-08  0:15             ` Nix
2012-02-08  1:51               ` Stefan Monnier
2012-02-08 23:43                 ` Nix
2012-02-09 21:34                   ` Stefan Monnier
2012-02-08  2:13           ` Stephen J. Turnbull
2012-02-08  2:19             ` Lennart Borgman
2012-02-08  4:23               ` Stephen J. Turnbull
2012-02-08 11:00                 ` Lennart Borgman
2012-02-08 17:42           ` Richard Stallman
2012-02-08 19:54             ` Stefan Monnier
2012-02-08  0:38         ` Daniel Colascione
2012-02-08  1:32           ` Lennart Borgman
2012-02-08  1:53           ` Stefan Monnier
2012-02-08  2:26             ` Daniel Colascione
2012-02-08 22:28       ` Lars Ingebrigtsen
2012-02-08 22:32         ` Lennart Borgman
2012-02-08 23:35         ` Nix
2012-02-09 19:42           ` Richard Stallman
2012-02-09 19:46             ` Nix
2012-02-10  1:09         ` John Wiegley
2012-02-10 14:38         ` Stefan Monnier
2012-02-10 15:08           ` Juanma Barranquero
2012-02-10 15:35             ` Drew Adams
2012-02-10 18:15               ` Stefan Monnier
2012-02-10 18:21                 ` Drew Adams
2012-02-10 15:24           ` Lars Ingebrigtsen
2012-02-10 18:24             ` Stefan Monnier
2012-02-10 18:26               ` Lars Ingebrigtsen
2012-02-10 18:47               ` Johan Bockgård
2012-02-10 17:12           ` Helmut Eller
2012-02-10 18:51             ` Stefan Monnier
2012-02-10 18:55               ` Lars Ingebrigtsen
2012-02-10 19:08               ` Teemu Likonen
2012-02-11 13:25                 ` Juanma Barranquero
2012-02-11 16:56                   ` Johan Bockgård
2012-02-11 22:33                     ` Juanma Barranquero
2012-02-12  4:41                 ` Stefan Monnier
2012-02-12 15:53                   ` Teemu Likonen
2012-02-12 16:52                     ` Stefan Monnier
2012-02-12 16:55                     ` Stefan Monnier
2012-02-10 23:56               ` Helmut Eller
2012-02-12  4:47                 ` Stefan Monnier
2012-02-12 17:39                   ` Helmut Eller
2012-02-12 18:15                     ` Stefan Monnier
2012-02-12 18:58                       ` Helmut Eller
2012-02-19 12:52         ` Dimitri Fontaine

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).