From: Bruno H. <br...@cl...> - 2017-07-19 21:00:32
|
[from clisp-list to clisp-devel] Sam, I mostly agree. > > 1) What should the syntax for this declaration look like? > > (Extension of DEFGENERIC? Separate declaration macro? ...) > > (defgeneric gf (...) > (declare (dynamically-modifiable)) > ...) Agree. The user will have to write (defgeneric gf (...) (declare #+clisp (dynamically-modifiable)) ...) because other implementations would choke on this declaration specifier ([1] says "other declaration specifiers are not permitted"). > > 2) Where should the information be stored? > > (In the generic-function object? On the symbol's property list? ...) > > generic-function object slot $dynamically-modifiable. Yep. Looks good. If someone redefines the GF, with a DEFGENERIC form without (dynamically-modifiable), it will warn about dynamic modifications. > (declaim (dynamically-modifiable gf1 gf2 gf3)) I don't think this will work right: If you store this information only in the GF, then after redefining the GF without (dynamically-modifiable), the effect will be lost - which is counter-intuitive. Whereas if you store this information on the property list of the symbol or in the undocumented variable clos::*dynamically-modifiable-generic-function-names*, the semantics will be too complex, i.e. too hard to understand. In summary, I would vote for - the DEFGENERIC syntax, - store the info in a slot in the GF, - don't offer DECLAIM support for it, - the only use of clos::*dynamically-modifiable-generic-function-names* will be for clos-genfun2b.lisp line 856. Bruno [1] http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec/Body/mac_defgeneric.html |
From: Sam S. <sd...@gn...> - 2017-07-19 21:30:21
|
Bruno, > * Bruno Haible <oe...@py...t> [2017-07-19 23:00:22 +0200]: > >> (declaim (dynamically-modifiable gf1 gf2 gf3)) > > I don't think this will work right: If you store this information only in > the GF, then after redefining the GF without (dynamically-modifiable), the > effect will be lost - which is counter-intuitive. Whereas if you store Not necessarily. When _redefining_ GF we can look at the old definition and carry the slot over to the new one, unless we also see (declare ((not dynamically-modifiable))) in the new definition. > this information on the property list of the symbol or in the undocumented > variable clos::*dynamically-modifiable-generic-function-names*, the > semantics will be too complex, i.e. too hard to understand. Then it will not be possible to change the dynamically-modifiable status of a GF without redefining it. I am not sure this is a good idea. BTW, we might want to also add (declaim ((not dynamically-modifiable) gf1 gf2 gf3)) > - the only use of clos::*dynamically-modifiable-generic-function-names* > will be for clos-genfun2b.lisp line 856. or no! please! we can do better: (letf (((gf-dynamically-modifiable gf) t)) (remove-method gf old-method)) Thanks. -- Sam Steingold (http://sds.podval.org/) on darwin Ns 10.3.1504 http://steingoldpsychology.com http://www.childpsy.net http://no2bds.org http://thereligionofpeace.com http://think-israel.org http://memri.org When C++ is your hammer, everything looks like a thumb. |
From: Daniel J. <dan...@gm...> - 2017-07-19 22:58:00
|
Hi Sam, Sam wrote: > Not necessarily. > When _redefining_ GF we can look > at the old definition and carry the > slot over to the new one, unless > we also see > > (declare ((not dynamically-modifiable))) > > in the new definition. Note that this may lead to situations where loading the exact same code will lead to different results, depending on previous definitions: a GF without any declare expression would be dynamically modifiable depending on whether there was a previous definition. As such the specification whether a GF is dynamically modifiable wouldn't be declarative ("declare" ??). Best, Daniel |
From: Sam S. <sd...@gn...> - 2017-07-20 15:10:29
|
Hi Daniel, > * Daniel Jour <qnavry.bregjvt@tznvy.pbz> [2017-07-19 22:57:40 +0000]: > > Note that this may lead to situations where loading the exact same code > will lead to different results, depending on previous definitions: This is already the case. If you have a file with (defun f (x) (lambda () (print x))) (funcall (f 10)) then loading it will print 10. If, however, you evaluate (defparameter x 100) before loading it, it will print 100. Note that the standard does NOT provide a way to revert the effects of defvar or defparameter. Note also the this whole conversation is related to warnings only, not the actual effect of the code. -- Sam Steingold (http://sds.podval.org/) on darwin Ns 10.3.1504 http://steingoldpsychology.com http://www.childpsy.net http://www.memritv.org http://honestreporting.com http://camera.org Two wrongs don't make a right, but three rights make a left. |
From: Bruno H. <br...@cl...> - 2017-07-20 17:08:29
|
Daniel wrote: > Note that this may lead to situations where loading the exact same code > will lead to different results, depending on previous definitions: a GF > without any declare expression would be dynamically modifiable depending on > whether there was a previous definition. Well explained. 100% agree. Sam wrote: > This is already the case. > If you have a file with > > (defun f (x) (lambda () (print x))) > (funcall (f 10)) > > then loading it will print 10. > If, however, you evaluate (defparameter x 100) before loading it, it > will print 100. This is precisely why DEFPARAMETER and DEFVAR are considered a problem in the CL language. The usual workaround is to separate the sets of symbols into two classes: those to which DEFPARAMETER and DEFVAR may be applied (those whose print name starts and ends with a * or + character) and those which, by convention (!), will not be subject to DEFPARAMETER or DEFVAR. Remember that this is merely a workaround to an ill design. It is not necessary to copy this ill design pattern to new areas, like generic functions. So, please, forget about DECLAIM here. > Then it will not be possible to change the dynamically-modifiable status > of a GF without redefining it. This is not a problem. The usual way of developing in any programming language, nowadays, is - to store the definitions in text files, - when making a change: change the file then LOAD it. The approach of InterLisp (change programs on-the-fly, in memory) became obsolete when the edit-file--reload--retry cycle became efficient enough. When you use closures e.g. (let ((balance 0)) (defun add (x) (incf balance x))) you cannot change the value of BALANCE, nor redefine ADD, without reloading the file. Yet this is considered completely normal programming style. Bruno |
From: Sam S. <sd...@gn...> - 2017-07-30 01:57:49
|
Bruno Why is class-direct-subclasses in *dynamically-modifiable-generic-function-names* but class-direct-superclasses not? Thanks. -- Sam Steingold (http://sds.podval.org/) on darwin Ns 10.3.1504 http://steingoldpsychology.com http://www.childpsy.net http://www.dhimmitude.org http://memri.org http://thereligionofpeace.com https://jihadwatch.org "A pint of sweat will save a gallon of blood." --George S. Patton |
From: Bruno H. <br...@cl...> - 2017-07-30 11:03:50
|
Hi Sam, > Why is class-direct-subclasses in > *dynamically-modifiable-generic-function-names* but > class-direct-superclasses not? When you look in the MOP (clisp/doc/mop-spec.pdf), pages 75..78, you see on page 78 an indication that the default method on class-direct-subclasses can be overridden. (Although I cannot imagine what such a method could do differently, assuming that the user has added overriding methods to add-direct-subclass and remove-direct-subclass. But it's in the spec...) No such indication is present for class-direct-superclasses. Bruno |