From: Sam S. <sd...@gn...> - 2008-12-30 19:32:55
|
Bruno, The error message for (close s :abort) is just about as bad as it ever gets: #:COMPILED-FORM-134-1: keyword arguments in (:ABORT) should occur pairwise This comes from one of the many "(eval ... (declare (compile)) ...)" forms in clos*.lisp. I wonder how it would be possible to pass a reasonable method name to the method function to overwrite the #:COMPILED-FORM-134-1 abomination. One idea I had was to allow the (compile) declaration to accept a function name, e.g.. (lambda () (declare (compile foo)) ...) ==> #<compiled-function foo> wdyt? Sam. |
From: Bruno H. <br...@cl...> - 2008-12-30 20:51:44
|
Sam, > The error message for (close s :abort) is just about as bad as it ever gets: > > #:COMPILED-FORM-134-1: keyword arguments in (:ABORT) should occur pairwise > > This comes from one of the many "(eval ... (declare (compile)) ...)" forms in > clos*.lisp. Yes. More precisely, from one of these: clos-class3.lisp: (DECLARE (COMPILE)) clos-class3.lisp: (DECLARE (COMPILE)) clos-class3.lisp: ,@(if *compile-accessor-functions* '((DECLARE (COMPILE)))) clos-class3.lisp: (DECLARE (COMPILE)) clos-class3.lisp: (DECLARE (COMPILE)) clos-class3.lisp: ,@(if *compile-accessor-functions* '((DECLARE (COMPILE)))) clos-genfun2b.lisp: (eval `(LET () (DECLARE (COMPILE) (INLINE FUNCALL APPLY)) clos-genfun2b.lisp:(defconstant *compile-no-jitc* '((OPTIMIZE (SPEED 0) (SPACE 3)) (COMPILE))) clos-method2.lisp: ,@(if compile '((DECLARE (COMPILE)))) > I wonder how it would be possible to pass a reasonable method name to the > method function to overwrite the #:COMPILED-FORM-134-1 abomination. > One idea I had was to allow the (compile) declaration to accept a function > name, e.g.. > (lambda () (declare (compile foo)) ...) ==> #<compiled-function foo> It's useful to be able to specify the function name not only for compiled, but also for interpreted function objects. :LAMBDA is not much friendlier than #:COMPILED-FORM-134-1. Therefore if it is to be a declaration, it should IMO be a different declaration: (lambda () (declare (compile) (function-name foo)) ...) ==> #<compiled-function foo> But actually clisp already has a non-standard extension for specifying the function object's name. It's in the FUNCTION special form: (FUNCTION foo (LAMBDA ...)) This works both in interpreted and compiled code: [1]> (function foo (lambda (x) x)) #<FUNCTION FOO (X) X> [2]> (function foo (lambda (x) (declare (compile)) x)) #<COMPILED-FUNCTION FOO> [3]> (locally (declare (compile)) (function foo (lambda (x) x))) #<COMPILED-FUNCTION FOO> However, in order to use this facility in clos-*.lisp, you would need to rewrite the (eval `(LET ...)) and similar constructs. Which would not be good for the clarity of the code, and would also cons too much when the (DECLARE (COMPILE)) is omitted. So, if I were you, I would 1) introduce a new declaration type SYS::FUNCTION-NAME or SYS::CLOSURE-NAME, and add it in *declaration-types* and process-declarations (in compiler.lisp), 2) take this declaration into account in compile-form (also compiler.lisp). Bruno |
From: Sam S. <sd...@gn...> - 2008-12-30 21:17:13
|
Bruno, > It's useful to be able to specify the function name not only for compiled, but > also for interpreted function objects. :LAMBDA is not much friendlier than > #:COMPILED-FORM-134-1. Therefore if it is to be a declaration, it should IMO good point. > be a different declaration: > (lambda () (declare (compile) (function-name foo)) ...) ==> #<compiled-function foo> > > But actually clisp already has a non-standard extension for specifying the > function object's name. It's in the FUNCTION special form: > (FUNCTION foo (LAMBDA ...)) > This works both in interpreted and compiled code: > > [1]> (function foo (lambda (x) x)) > #<FUNCTION FOO (X) X> > [2]> (function foo (lambda (x) (declare (compile)) x)) > #<COMPILED-FUNCTION FOO> > [3]> (locally (declare (compile)) (function foo (lambda (x) x))) > #<COMPILED-FUNCTION FOO> alas, it does not work with backslashes: (function foo `(lambda (x) ,...)) bombs. since this is an extension anyway, I think it would make sense to extend it to handle the above too, using (coerce ... 'function). > However, in order to use this facility in clos-*.lisp, you would need to > rewrite the (eval `(LET ...)) and similar constructs. Which would not be > good for the clarity of the code, and would also cons too much when the > (DECLARE (COMPILE)) is omitted. > > So, if I were you, I would > 1) introduce a new declaration type SYS::FUNCTION-NAME or SYS::CLOSURE-NAME, > and add it in *declaration-types* and process-declarations (in compiler.lisp), > 2) take this declaration into account in compile-form (also compiler.lisp). the only use this declaration would have is with interpreted non-constant (i.e., created by backslashes) lambdas: if a lambda is constant, (function foo (lambda (...)...)) wins. if a lambda is compiled, (lambda (...) (declare (compile foo)) ...) wins (since the (compile) declaration implies that the lambda will never morph into an interpreted closure). do we have many of those? Sam. |
From: Bruno H. <br...@cl...> - 2008-12-31 00:12:42
|
Sam, > alas, it does not work with backslashes: > > (function foo `(lambda (x) ,...)) > > bombs. (eval `(function foo (lambda (x) ,...))) should work > since this is an extension anyway, I think it would make sense to extend it to > handle the above too, using (coerce ... 'function). Good point. Yes, get_closure should look whether it finds a declaration, at the top-level of the lambdabody, which specifies the function name. It will then override (or be overridden by) the function name passed as argument of get_closure. > > So, if I were you, I would > > 1) introduce a new declaration type SYS::FUNCTION-NAME or SYS::CLOSURE-NAME, > > and add it in *declaration-types* and process-declarations (in compiler.lisp), > > 2) take this declaration into account in compile-form (also compiler.lisp). > > the only use this declaration would have is with interpreted non-constant > (i.e., created by backslashes) lambdas: > if a lambda is constant, (function foo (lambda (...)...)) wins. > if a lambda is compiled, (lambda (...) (declare (compile foo)) ...) wins (since > the (compile) declaration implies that the lambda will never morph into an > interpreted closure). > do we have many of those? This is a misunderstanding: what I wrote above was a hint about how to implement the feature with the least effort. Forget about it. Back to the feature itself. The proposal is to introduce a new declaration, EXT:FUNCTION-NAME. (DECLARE (EXT:FUNCTION-NAME name)) can be used in a lambda expression or a form, as a hint, which name to use for the function object that will at runtime represent that form or function object. name must be a function name (type (OR SYMBOL (CONS (EQL SETF) (CONS SYMBOL NULL)))). The declaration makes sense in lambda expressions and, in forms, in combination with the (COMPILE) declaration. In other situations, the declaration is ignored because no function object is created. The declaration may also be ignored in other situations where no function object is created, for example, when the lambda expression is inlined. At the same time, the function SYS::FUNCTION-NAME will be exported from the EXT package. There is no relation between EXT:FUNCTION-NAME as a declaration specifier and EXT:FUNCTION-NAME as a function name, other than they happen to be the same symbol. (IF we don't export this symbol, we get a nasty package conflict.) Unit tests: (function-name (function (lambda (x y) (declare (function-name plus)) (+ x y)))) PLUS (function-name (function (lambda (x y) (declare (compile) (function-name plus)) (+ x y)))) PLUS (function-name (function sum (lambda (x y) (declare (function-name plus)) (+ x y)))) SUM ; or PLUS ? what do you prefer? (function-name (function sum (lambda (x y) (declare (compile) (function-name plus)) (+ x y)))) SUM ; or PLUS ? what do you prefer? (function-name (coerce '(lambda (x y) (declare (function-name plus)) (+ x y)) 'function)) PLUS (function-name (eval `(locally (function (lambda (x y) (declare (function-name plus)) (+ x y)))))) PLUS (function-name (eval `(locally (declare (compile)) (function (lambda (x y) (declare (function-name plus)) (+ x y)))))) PLUS (function-name (eval `(let () (function (lambda (x y) (declare (function-name plus)) (+ x y)))))) PLUS (function-name (eval `(let () (declare (compile)) (function (lambda (x y) (declare (function-name plus)) (+ x y)))))) PLUS (function-name (eval `(let* () (function (lambda (x y) (declare (function-name plus)) (+ x y)))))) PLUS (function-name (eval `(let* () (declare (compile)) (function (lambda (x y) (declare (function-name plus)) (+ x y)))))) PLUS Does this sound good? Don't think about backquotes at this point. Backquote is just a shorthand notation for list construction. Bruno |
From: Sam S. <sd...@gn...> - 2008-12-31 16:55:53
|
Bruno >> alas, it does not work with backslashes: >> >> (function foo `(lambda (x) ,...)) >> >> bombs. > > (eval `(function foo (lambda (x) ,...))) > should work I shudder every time I see EVAL in the code... > (function-name (function sum (lambda (x y) (declare (function-name plus)) (+ x y)))) > SUM ; or PLUS ? what do you prefer? SUM: the later (FUNCTION ...) overrides the earlier (DECLARE (FUNCTION-NAME ...)) > Does this sound good? I prefer adding an argument to the (DECLARE (COMPILE [name])) declaration. This results in a more compact code and fewer symbols to handle in declaration parsers. Sam. PS. please take a look: http://clisp.podval.org/impnotes/declarations.html#compile-decl why is (compile) declaration ignored in LABELS, FLET and MACROLET? |
From: Sam S. <sd...@gn...> - 2008-12-31 19:09:42
|
Bruno, getting back to the original problem, I now get (close *standard-output* :ab) *** - COMMON-LISP::CLOSE-<EMF-1>-1: keyword arguments in (:AB) should occur pairwise this is much better than #:COMPILED-FORM-133-1, but it could be improved, e.g., buy using ;; better naming of effective method functions (defun effective-method-function-name (gf methods) (sys::symbol-suffix (sys::closure-name gf) (princ-to-string (car methods)))) in clos-print.lisp, after CLOS has been built. alas, I run into a bootstrapping problem here: printing a method object for the first time creates an effective method function for PRINT-OBJECT - and the stack blows because of infinite recursion. I tried this: (defun effective-method-function-name (gf methods) (sys::symbol-suffix (sys::closure-name gf) (with-output-to-string (o) (princ "<EMF-[" o) (format o "~{~A~^@~}" (mapcar #'class-name (method-specializers (car methods)))) (princ "]>" o)))) with the exact same result - stack overflow, even though I am only printing symbols, not CLOS objects. any ideas? Sam. |