[cells-devel] Re: It's not a feature, it's a bug

Thomas F. Burdick tfb at OCF.Berkeley.EDU
Fri Nov 7 06:51:55 UTC 2003


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+ ?

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               




More information about the cells-devel mailing list