[Prev][Next][Index][Thread]

Re: Need help with Class-Allocated Slots



On 27 Jun 2000, Neel Krishnaswami wrote:
> Andreas Bogk <andreas@andreas.org> wrote:
> > "Scott McKay" <swm@mediaone.net> writes:
> > 
> > > During the design of Dylan, I proposed that class slots be accessible
> > > by calling the accessor on the class object itself, but Moon didn't like
> > > it because it confuses class vs. instance.  I agree with Moon on the
> > > exact point, but I still think that the semantics of my dumb-ass proposal
> > > are well enough understood, that it is probably reasonable.
> > 
> > Maybe it's time to resurrect the Dylan Language discussion at
> > 
> > http://www.isr.com/dylan/dylan-language/
> > 
> > I agree that it should be possible to access class slots without
> > having an instance.
> 
> The big problems with this that is it's hard to know what to do if
> there is a specialized method shadowing the basic getter. For example:
> 
>   define class <super> (<object>)
>      class slot foo :: <integer>,
>        init-value: 6;
>   end class;
> 
>   define class <perverse-subclass> (<super>)
>     slot bar :: <integer>,
>       init-value: 24;
>   end class;
> 
>   define method foo (obj :: <perverse-subclass>, #next next-method)
>     obj.bar * next-method()
>   end method;
> 
> Then it's totally unclear what you should return with a method like
> 
>   class-slot(class, getter-generic)
> 
> when you call class-slot(<perverse-subclass>, foo). IMO, in this case,
> half a loaf is definitely worse than either no loaf. 

Uh, what "class-slot" method would that be, then? ;-)  Dylan specifically
doesn't let you ask a class about its slots (or its instances), though you
can ask about its sub- and superclasses.  (You might get an exception
thrown for sealed subclasses, though.)  Do you mean you'd want to write
such a "pseudo-reflection" GF yourself?

In any case, it seems to me that, if you want class slots accessible
without instances (and I think that's a good idea) then these slots
would better belong to the class, rather than just be held by it on behalf
of all instances.  Then, given your class <super> above, you would write
things like

  <super>.foo := <super>.foo + 1;

I.e., you effectively have accessor methods with signatures like

  define method foo (class == <super>)
   => (foo :: <integer>);
  define method foo-setter (new-foo :: <integer>, class == <super>)
   => (foo :: <integer>);

(and similarly for each-subclass slots, but using
  "class :: subclass(<super>)"
).

For convenience and backward compatibility, it might make sense to also
add accessor methods equivalent to:

  define method foo (super :: <super>) => (foo :: <integer>)
    super.object-class.foo
  end;
  define method foo-setter (new-foo :: <integer>, class == <super>)
   => (foo :: <integer>)
    super.object-class.foo := new-foo;
  end;

There's still the question of whether it should be allowable to override
these methods (both class-accessed and instance-accessed) in subclasses
(assuming no sealing prevents it), potentially changing the
effective allocation.  I think the answer has to be "yes", because you can
already do that for all kinds of slots in Dylan.


BTW, there was an interesting article in the March/April 2000 issue of
JOOP (Vol. 13, No. 1), on "A Critical Comparison of Class Variables and
Methods".  It looked at C++, Eiffel, Beta, Java and Smalltalk [wot, no
CLOS?!].  Of these, only Smalltalk fitted the author's criteria of
handling class-associated state and functions in a general and orthogonal
way.

In Dylan terms ...

- Some (C++, Eiffel, Java) allowed "class" data but not "each-subclass" 
data.  (Dylan passes here.) 

- Some (C++, Java) didn't allow extending class-specialised methods (which
would be "virtual static" methods in C++), only overriding them.  (Dylan
passes here, as all inheritance and specialisation is equivalent to C++'s
"virtual".  If you really want the C++ effect of overriding a function on
a superclass, you'd have to rename or exclude it on import to your module
and then write a new function of the same name.) 

- Beta, well, it's just weird ;-P  (You could do class data but only with
an extra level of hair which made "classes" using class-allocation appear
quite different from those which didn't.  I don't think you could do
class methods at all.) 

The only place Dylan falls down is that, unlike Java, C++ and Smalltalk,
you can't access per-(sub)class data without an instance.


Oh yeah, one last thing.  Another slight semantic change(?) if we can
access class slots via classes is that data stored in them can't ever be
GCd (until it's replaced, or the class itself is GCd).  In the current
scheme, it's not clear whether, whenever all instances of a class with
class slots have been GCd, the data in the class slots should also be GCd.
I don't think this is a point against making class slots accessible via
the classes; I just mention it in case it would change the semantics of
any existing code.


Hugh




Follow-Ups: References: