Thomas F. Burdick wrote:
Kenny Tilton writes:
Turns out I /do/ try to reset an ephemeral initialized to (CV <not nil>), but I only reset the cached value slot of the cell, not the slot-value per se. And the slot-value is the place the accessor looks for a value. The cache is just used for other stuff. Ah, the hazards of redundant representation.
Writing a simple KR<-->CLOS bridge was easy, but not subtly screwing up the duplicated information was kind of a headache, so I can sympathize.
Anyway, I think we are agreeing to let ephemeral + (CV <whatever>) signify that <whatever> is the value to revert to after a later ephemeral datachange for such a slot. Hmmm, let me thnk about this. I actually saw this bug and might have it in a do-list somewhere. I think it came up because I wanted a non-nil initial value for a nil-based ephemeral slot at make-instance-time.
Yep, we're in agreement. This would be very useful for ephemeral slots that take on numeric values, and for interacting well with type declarations. In SBCL, declarations = assertions (CMUCL too, but SBCL takes it more seriously), so you can do something like:
(defclass foo () ((a :accessor foo-a :type fixnum)))
and if you try to set an A slot to something other than a fixnum, you'll get a runtime error.
Good lord. Do they know CL is short for Common Lisp? Tell me they get huge runtime performance benefits from this sacrilege.
Actually, there is a problem here. Currently Cell structures land in the slot during make-instance (when I had a MOP-based implementation I shunted Cells bound for a slot over to the .cells internals slot before they ever got to the slot, by placing an around method on (setf slot-value-using-class)). Possibly I can do the same with an around meth on shared-initialize, but till then SBCL will likely not be happy with a Cell in a slot typed numeric.
Well, we'll put this in the hopper, but I propose we give higher priority to me documenting the system and getting Cello going. And I think I do want to make the resumed base value (what /do/ we call that?) of an ephemeral a distinct attribute, so as not to shadow the semantics of an instance being initialized with an ephemeral slot initialized, say, (CV 2) with baseline value zero.
Plus, you get compile-time warnings if Python's type inference shows that A could be set to a non-fixnum.
One problem with Cell-as-is on SBCL, is that the type checking only happens when you use the accessor function, not SLOT-VALUE. This is probably best considered a bug in SBCL's PCL, but it has the following unfortunate result:
- (defmodel foo () ((x :initform (cv 0) :accessor get-x :type fixnum) (10x :initform (c? (* 10 (get-x self))) :accessor get-10x :type fixnum)))
STYLE-WARNING: redefining SHARED-INITIALIZE :AFTER (FOO T) in DEFMETHOD
Hey, SBCL is creating an after method on shared-initialize?
STYLE-WARNING: redefining GET-X (FOO) in DEFMETHOD STYLE-WARNING: redefining (SETF GET-X) (T FOO) in DEFMETHOD STYLE-WARNING: redefining GET-10X (FOO) in DEFMETHOD STYLE-WARNING: redefining (SETF GET-10X) (T FOO) in DEFMETHOD
<heh-heh> I keep wondering my I do not get "get-10x defined twice in foo.lisp" et al, but I do not.
#<STANDARD-CLASS FOO>
- (setf >>foo (make-instance 'foo))
FOO
- (get-10x >>foo)
0
- (setf (get-x >>foo) most-positive-fixnum)
536870911
- (get-10x >>foo)
5368709110
- (typep * 'fixnum)
NIL
Gee, what /is/ the type?
In reverse order of simplicity, the best way to solve this would be to fix SBCL;
Have you asked the SBCL crowd whether they are set on slot-value being type-ignorant?
the second best way would be to either have Cells use :around methods, instead of redefining the primary methods, then invoke the proper next-method machinery
That scares me.in the abstract, tho I cannot point to any evil consequence, I just think one will arise in due course because it strikes me as a kluge.
-- or, have Cells propagate the type declaration to its new method definitions.
That should be easy, and sounds Deeply Correct. I am already looking at the slot definition name to get reader and writer names, may as well grab the type if any. So what's the syntax for declaring a /return/ type? And the synatx on the setf side as well.
Since we've got eager data propogation, it would be nice to get the type errors with the stack still intact. Obviously, though, this can wait for a bit (although I might make it one of my higher priorities once Cells is in CVS).
I hear a vote for early CVS. :)
Tell you what, I owe common-lisp.net a release, let me just fix the bug so a (cv 2) does get reset as advertised and the doc is accurate, then we can study this. I might want to change the syntax from :cell :ephemeral to ":cell t :ephemeral-resumes <whatever>" where by the new scheme the :cell t is unnecesary since that's the default, but anyway. Then :ephemeral-resumes is a two-fer, it gives you ephemrality as well as specifying the value to resume after a change.
Hmm, :ephemeral-resumes seems like a weird name. Maybe :ephemeral-default ? Actually, I think it would be better to stick with the :cell :ephemeral :initform ( syntax
In RMS (an ISAM) one could specify that spaces or all zeros or whatever were the NULL_VALUE for an alternate key, meaning "if this is my value for this indexed field, just leave me the hell out of that index; i cannot be found that way". This was crucial where an indexed field was populated by only one or two percent weirdo records. Without NULL-VALUE, you get a million records with the same duplicate value, and an insertion could take 30 seconds as RMS read through a vast index tree looking for the place to insert. How is:
:cell :ephemeral :c-null-value 0 :initform (cv 0)
I just feel kinda bad making them type in the initform when at this point DEFMODEL has enough info to auto-supply that (and I do frequently neglect to code in (cv nil) on ephemerals. Should we add that nicety? Do we need a warning if they say :c-null-value and they do not say :ephemeral? The parallel error went unnoticed on an RMS file with consequences you would not believe.
The nice thing about the suggested alternative
:ephemeral-resumes 0 (with :cell t by default,and of course a better name)
is that it eliminates the redundant declaration
kenny
Kenny Tilton writes:
Thomas F. Burdick wrote:
(defclass foo () ((a :accessor foo-a :type fixnum)))
and if you try to set an A slot to something other than a fixnum, you'll get a runtime error.
Good lord. Do they know CL is short for Common Lisp? Tell me they get huge runtime performance benefits from this sacrilege.
(What about "Steel Bank" says "fast and loose"? ;) Taking the CL type system seriously has a few benefits, one of which is can be being able to emit blazingly fast object code, but a big one is debugability. Unlike crummy languages, there's no reason you have to declare any types anywhere -- but if you *do*, you get runtime assurances. And with structures or objects, the big win is not scratching your head, wondering, "well how in the hell did NIL get *there*?". Instead, you can look at the stack exactly when NIL got there. But it's CL, so if you just want your cake, but don't want to eat it (you just like the way it looks perhaps?), you don't have to declare a single type anywhere.
Actually, there is a problem here. Currently Cell structures land in the slot during make-instance (when I had a MOP-based implementation I shunted Cells bound for a slot over to the .cells internals slot before they ever got to the slot, by placing an around method on (setf slot-value-using-class)). Possibly I can do the same with an around meth on shared-initialize, but till then SBCL will likely not be happy with a Cell in a slot typed numeric.
Well, right now, any value can actually go in a slot with a declared type: type checking only happens if you go through the accessor method. Cells-for-structures wouldn't work so hot, though.
Well, we'll put this in the hopper, but I propose we give higher priority to me documenting the system and getting Cello going.
Definately. I'm partly just bouncing ideas off of you, and if they seem workable, I'll make the changes myself, if I need them.
And I think I do want to make the resumed base value (what /do/ we call that?)
an at-rest value?
of an ephemeral a distinct attribute, so as not to shadow the semantics of an instance being initialized with an ephemeral slot initialized, say, (CV 2) with baseline value zero.
Okay, so the initial value would be just another value it takes on ephemerally, before going back to its resting state?
STYLE-WARNING: redefining SHARED-INITIALIZE :AFTER (FOO T) in DEFMETHOD
Hey, SBCL is creating an after method on shared-initialize?
Oops, that was TFB that did that, not SBCL.
5368709110
- (typep * 'fixnum)
NIL
Gee, what /is/ the type?
Too much? Actually, the answer is kind of amusing. CMUCL would tell you BIGNUM. SBCL, however, is a tiny bit more precise:
* (type-of 5368709110)
(INTEGER 536870912)
Did I mention they take the type system seriously?
In reverse order of simplicity, the best way to solve this would be to fix SBCL;
Have you asked the SBCL crowd whether they are set on slot-value being type-ignorant?
I'd assume just the opposite, that they consider it a bug (it seems like a gap in declarations-as-assertions), but I don't see it in the BUGS file, so maybe I'm wrong. I'll ask.
the second best way would be to either have Cells use :around methods, instead of redefining the primary methods, then invoke the proper next-method machinery
That scares me.in the abstract, tho I cannot point to any evil consequence, I just think one will arise in due course because it strikes me as a kluge.
Ooh, yeah, that might do bad things if you have one model that inherits from another (the next-method would be the superclass' :around method).
-- or, have Cells propagate the type declaration to its new method definitions.
That should be easy, and sounds Deeply Correct. I am already looking at the slot definition name to get reader and writer names, may as well grab the type if any. So what's the syntax for declaring a /return/ type? And the synatx on the setf side as well.
This seems like a good thing for Cells to do, because that way type declarations can more fully do their thing, whatever that means on the implementation you're using. For syntax:
* (macroexpand-1 '(defmodel foo () ((x :initform (cv 0) :accessor get-x :type fixnum) (10x :cell t :accessor get-10x :type fixnum))))
...
(PROGN (DEFMETHOD GET-X ((SELF FOO)) (CELLS::MD-SLOT-VALUE SELF 'X)) (DEFMETHOD (SETF GET-X) (NEW-VALUE (SELF FOO)) (SETF (CELLS::MD-SLOT-VALUE SELF 'X) (COERCE NEW-VALUE 'FIXNUM))) NIL)
(Holy crap, where'd that COERCE come from? That's not a good idea at all, you can lose object identity that way.)
With type declarations, that would be:
(progn (defmethod get-x ((self foo)) (declare (values fixnum)) ; <==== (cells::md-slot-value self 'x)) (defmethod (setf get-x) (new-value (self foo)) (declare (type fixnum new-value)) (setf (cells::md-slot-value self 'x) new-value)) nil)
Problem is, the type-checks don't go deeply enough into cells this way. If we propagage the type declarations for 10X in the same way, we get:
(progn (defmethod get-10x ((self foo)) (declare (values fixnum)) (cells::md-slot-value self '|10X|)) (defmethod (setf get-10x) (new-value (self foo)) (declare (type fixnum new-value)) (setf (cells::md-slot-value self '|10X|) new-value)) nil)
But when X is changed, and 10X is recalculated, this method doesn't get invoked.
[ Plus, SBCL can't check (VALUES ...) declarations yet, grrr. You'd have to do something ugly like:
(defmethod get-x ((self foo)) (let ((result (cells::md-slot-value self '10x))) (the fixnum result))) ]
Since we've got eager data propogation, it would be nice to get the type errors with the stack still intact. Obviously, though, this can wait for a bit (although I might make it one of my higher priorities once Cells is in CVS).
I hear a vote for early CVS. :)
Yeah, let's get your next .zip into CVS.
Hmm, :ephemeral-resumes seems like a weird name. Maybe :ephemeral-default ? Actually, I think it would be better to stick with the :cell :ephemeral :initform ( syntax
I managed to hit Send on accident here. That was supposed to end:
with the :cell :ephemeral :initform (cv ...) syntax, because then you could have the slot-value default to being unbound.
In RMS (an ISAM) one could specify that spaces or all zeros or whatever were the NULL_VALUE for an alternate key, meaning "if this is my value for this indexed field, just leave me the hell out of that index; i cannot be found that way". This was crucial where an indexed field was populated by only one or two percent weirdo records. Without NULL-VALUE, you get a million records with the same duplicate value, and an insertion could take 30 seconds as RMS read through a vast index tree looking for the place to insert. How is:
:cell :ephemeral :c-null-value 0 :initform (cv 0)
I just feel kinda bad making them type in the initform when at this point DEFMODEL has enough info to auto-supply that (and I do frequently neglect to code in (cv nil) on ephemerals. Should we add that nicety? Do we need a warning if they say :c-null-value and they do not say :ephemeral? The parallel error went unnoticed on an RMS file with consequences you would not believe.
The only problem I'd have with auto-supplying an initform is that you can't have it be unbound when at rest. Well, I guess you could have a cells:+unbound-value+, which says, "I don't want NIL, I want this unbound".
The nice thing about the suggested alternative
:ephemeral-resumes 0 (with :cell t by default,and of course a
better name)
is that it eliminates the redundant declaration
I guess the verbose option makes the common case pretty annoying, for the dubious value of allowing unbound as an option. Maybe :ephemeral-resting-value <at-rest-value>, plus a cells:+unbound+ ?
Thomas F. Burdick wrote:
Kenny Tilton writes:
Thomas F. Burdick wrote:
(defclass foo () ((a :accessor foo-a :type fixnum)))
and if you try to set an A slot to something other than a fixnum, you'll get a runtime error.
Good lord. Do they know CL is short for Common Lisp? Tell me they get huge runtime performance benefits from this sacrilege.
(What about "Steel Bank" says "fast and loose"? ;) Taking the CL type system seriously has a few benefits, one of which is can be being able to emit blazingly fast object code, but a big one is debugability.
gotcha.
Actually, there is a problem here. Currently Cell structures land in the slot during make-instance ...
Well, right now, any value can actually go in a slot with a declared type: type checking only happens if you go through the accessor method.
Oh, right, you said that. I thought I heard a concern that nil could not be a NULL-VALUE for a slot with an explicit numeric type specified. Oh, well, still a good idea to capture type info for the accessors Cells writes.
Cells-for-structures wouldn't work so hot, though.
Well, we'll put this in the hopper, but I propose we give higher priority to me documenting the system and getting Cello going.
Definately. I'm partly just bouncing ideas off of you, and if they seem workable, I'll make the changes myself, if I need them.
The marines have landed!
And I think I do want to make the resumed base value (what /do/ we call that?)
an at-rest value?
Not bad. I had toyed with quiesce-to.... restore-to? stable-value? fallback-value?
of an ephemeral a distinct attribute, so as not to shadow the semantics of an instance being initialized with an ephemeral slot initialized, say, (CV 2) with baseline value zero.
Okay, so the initial value would be just another value it takes on ephemerally, before going back to its resting state?
Yep. the only problem is that I would have to arrange for ephemrals initialized this way to hang on to non-resting values until all other cells (in all instances being awakened in one batch) had been kicked off, because at make-instance time (well, at TO-BE time) the sytems has not stabilized with all dependencies in place, so an ephemeral does not know who to notify.
This is getting ugly. I think I'll go with resting-value because as a rule I like explicit, then wait for initialization to non-resting to come up a again so I can think more clearly about the problem.
STYLE-WARNING: redefining SHARED-INITIALIZE :AFTER (FOO T) in DEFMETHOD
Hey, SBCL is creating an after method on shared-initialize?
Oops, that was TFB that did that, not SBCL.
whew! but then we have a problem? Oh, I see, just that dumb check that someone does not use defmodel then specify superclasses, none of which inherit from model-object. I wonder if that is necessary? They'll find out soon enough (tho it could take a while to figure out. )
5368709110
- (typep * 'fixnum)
NIL
Gee, what /is/ the type?
Too much? Actually, the answer is kind of amusing. CMUCL would tell you BIGNUM. SBCL, however, is a tiny bit more precise:
- (type-of 5368709110)
(INTEGER 536870912)
Did I mention they take the type system seriously?
In reverse order of simplicity, the best way to solve this would be to fix SBCL;
Have you asked the SBCL crowd whether they are set on slot-value being type-ignorant?
I'd assume just the opposite, that they consider it a bug (it seems like a gap in declarations-as-assertions), but I don't see it in the BUGS file, so maybe I'm wrong. I'll ask.
the second best way would be to either have Cells use :around methods, instead of redefining the primary methods, then invoke the proper next-method machinery
That scares me.in the abstract, tho I cannot point to any evil consequence, I just think one will arise in due course because it strikes me as a kluge.
Ooh, yeah, that might do bad things if you have one model that inherits from another (the next-method would be the superclass' :around method).
-- or, have Cells propagate the type declaration to its new method definitions.
That should be easy, and sounds Deeply Correct. I am already looking at the slot definition name to get reader and writer names, may as well grab the type if any. So what's the syntax for declaring a /return/ type? And the synatx on the setf side as well.
This seems like a good thing for Cells to do, because that way type declarations can more fully do their thing, whatever that means on the implementation you're using. For syntax:
- (macroexpand-1 '(defmodel foo () ((x :initform (cv 0) :accessor get-x :type fixnum) (10x :cell t :accessor get-10x :type fixnum))))
...
(PROGN (DEFMETHOD GET-X ((SELF FOO)) (CELLS::MD-SLOT-VALUE SELF 'X)) (DEFMETHOD (SETF GET-X) (NEW-VALUE (SELF FOO)) (SETF (CELLS::MD-SLOT-VALUE SELF 'X) (COERCE NEW-VALUE 'FIXNUM))) NIL)
(Holy crap, where'd that COERCE come from? That's not a good idea at all, you can lose object identity that way.)
With type declarations, that would be:
(progn (defmethod get-x ((self foo)) (declare (values fixnum)) ; <==== (cells::md-slot-value self 'x)) (defmethod (setf get-x) (new-value (self foo)) (declare (type fixnum new-value)) (setf (cells::md-slot-value self 'x) new-value)) nil)
Problem is, the type-checks don't go deeply enough into cells this way. If we propagage the type declarations for 10X in the same way, we get:
(progn (defmethod get-10x ((self foo)) (declare (values fixnum)) (cells::md-slot-value self '|10X|)) (defmethod (setf get-10x) (new-value (self foo)) (declare (type fixnum new-value)) (setf (cells::md-slot-value self '|10X|) new-value)) nil)
But when X is changed, and 10X is recalculated, this method doesn't get invoked.
If DEFMODEL stuffs type info by slot and class into some global hash or property list, at make-instance time we can pull the type info into a dedicated slot in the cell structure. would that help in anyway? Looks like THE cannot use a dynamic type.
Hey, I put in the serialize option and now ASDF compiles but does not load (until the end I guess), so later compiles don't see earlier stuff. (Some serial!) . I tried coding up:
:perform (compile-op :after (op c) (load c))
but i was just guessing wildly. What's the incantation to get ADF to load as it goes?
kt
Kenny Tilton writes:
Thomas F. Burdick wrote:
(defclass foo () ((a :accessor foo-a :type fixnum)))
and if you try to set an A slot to something other than a fixnum, you'll get a runtime error.
Okay, I need to lay of the crack a little. PCL is not so well integrated into SBCL as all this. What I said applies to instances of structure-class, when defined with defstruct, but not any kind of anything you can define with defclass. Oops. It's still something that should happen when PCL is better integrated, though.
Me again:
-- or, have Cells propagate the type declaration to its new method definitions.
I would still like to see this, though. Hell, maybe cells:defmodel will behave more in line with declarations=assertions than cl:defclass
If DEFMODEL stuffs type info by slot and class into some global hash or property list, at make-instance time we can pull the type info into a dedicated slot in the cell structure. would that help in anyway? Looks like THE cannot use a dynamic type.
Lemme think about this. I bet we could have DEFMODEL construct stash a reader/setter pair away somewhere and use them instead of SLOT-VALUE. There's gotta be some inoffensive way to leverage the host CL's type system's abilities.