Need help with Class-Allocated Slots
Author |
Message |
Ron Franke-pol #1 / 31
|
 Need help with Class-Allocated Slots
I've been playing around with slot allocation and am wondering if there is a way to access "class allocated" slots without having an instance of that class? Here's an example: // ==================================================== // <bookkeeping-class> // // - a class that keeps track any instances created // ==================================================== define class <bookkeeping-class> (<object>) class slot all-instances :: <list>, init-value: #(); each-subclass slot class-instances :: <list>, init-value: #(); end class; // initialize // define method initialize (a :: <bookkeeping-class>, #keys) next-method(a); a.all-instances := add(a.all-instances, a); a.class-instances := add(a.class-instances, a); end method; // ==================================================== Now, if I instanciate any number of instances of this class (or sub-classes), and I have an instance, I can get the list of all instances; // ==================================================== let node = make(<bookkeeping-node>); let instance-list = node.all-instances; // ==================================================== This works, but I have to create a "dummy" instance to get access to the instance list(s). Then, I have to "remove" the dummy instance. What I would like to do is, given the class, get all of the instances; // ==================================================== // hacked-up syntax let instance-list = <bookkeeping-node>.all-instances; // ==================================================== I've been looking through the DRM, and there aren't too many examples of class-allocated slots. Language lawyers - any ideas? Thanks, Ron Franke-Polz
|
Sun, 08 Dec 2002 03:00:00 GMT |
|
 |
Eric Gourio #2 / 31
|
 Need help with Class-Allocated Slots
Quote:
> I've been playing around with slot allocation and am wondering if there is a > way to access "class allocated" slots without having an instance of that > class?
No, and it has been a problem for me in the past. Regards - Eric --
|
Sun, 08 Dec 2002 03:00:00 GMT |
|
 |
Chris Doubl #3 / 31
|
 Need help with Class-Allocated Slots
Quote:
> I've been playing around with slot allocation and am wondering if there is a > way to access "class allocated" slots without having an instance of that > class?
There was a discussion on this last year I think when the singleton design pattern was discussed. It turns out there is no way of accessing the class or each-subclass slots without an instance of the class. One possible work around is not to use the class allocated slot but to use a normal function accessing a global variable or some similar scheme. Chris. -- http://www.double.co.nz/dylan
|
Mon, 09 Dec 2002 03:00:00 GMT |
|
 |
Jason Trenout #4 / 31
|
 Need help with Class-Allocated Slots
Quote:
> > I've been playing around with slot allocation and am wondering if there is a > > way to access "class allocated" slots without having an instance of that > > class? > There was a discussion on this last year I think when the singleton > design pattern was discussed. It turns out there is no way of > accessing the class or each-subclass slots without an instance of the > class. > One possible work around is not to use the class allocated slot but to > use a normal function accessing a global variable or some similar > scheme.
This was probably mentioned the last time this topic came around, but one could use a class allocated slot, a singleton, and wrap the access to give the feel of direct access. define class <foo> (<object>) class slot foo-bar = #f, init-keyword: bar:; end class; define constant $foo = make(<foo>); define method foo-bar ( x == <foo> ) foo-bar( $foo ); end method; The downside is that making an instance may be costly or have resources associated with it that are inappropriate for such a prototype, but you could introduce a subclass which was specialized for this purpose. __Jason _____________________________________________________________________ This message has been checked for all known viruses by Star Internet delivered through the MessageLabs Virus Control Centre. For further information visit http://www.star.net.uk/stats.asp
|
Mon, 09 Dec 2002 03:00:00 GMT |
|
 |
r.. #5 / 31
|
 Need help with Class-Allocated Slots
Forgive me for asking the obvious, as I am sure it has been stated before if this was discussed previously, but why isn't a direct mechanism for accessing class slots designed into the language? Quote:
> > > I've been playing around with slot allocation and am wondering if there is a > > > way to access "class allocated" slots without having an instance of that > > > class? > > There was a discussion on this last year I think when the singleton > > design pattern was discussed. It turns out there is no way of > > accessing the class or each-subclass slots without an instance of the > > class. > > One possible work around is not to use the class allocated slot but to > > use a normal function accessing a global variable or some similar > > scheme. > This was probably mentioned the last time this topic came around, but one could > use a class allocated slot, a singleton, and wrap the access to give the feel > of direct access. > define class <foo> (<object>) > class slot foo-bar = #f, init-keyword: bar:; > end class; > define constant $foo = make(<foo>); > define method foo-bar ( x == <foo> ) > foo-bar( $foo ); > end method; > The downside is that making an instance may be costly or have resources > associated with it that are inappropriate for such a prototype, but you could > introduce a subclass which was specialized for this purpose. > __Jason > _____________________________________________________________________ > This message has been checked for all known viruses by Star Internet delivered > through the MessageLabs Virus Control Centre. For further information visit > http://www.star.net.uk/stats.asp
|
Mon, 09 Dec 2002 03:00:00 GMT |
|
 |
Scott McKa #6 / 31
|
 Need help with Class-Allocated Slots
Quote: >Forgive me for asking the obvious, as I am sure it has been stated >before if this was discussed previously, but why isn't a direct >mechanism for accessing class slots designed into the language?
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. Quote:
>> > > I've been playing around with slot allocation and am wondering if there is a >> > > way to access "class allocated" slots without having an instance of that >> > > class?
|
Tue, 10 Dec 2002 03:00:00 GMT |
|
 |
Andreas Bog #7 / 31
|
 Need help with Class-Allocated Slots
Quote:
> 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. Andreas -- "C++ is history repeated as tragedy. Java is history repeated as farce." -- Scott McKay
|
Sat, 14 Dec 2002 03:00:00 GMT |
|
 |
Neel Krishnaswa #8 / 31
|
 Need help with Class-Allocated Slots
Quote:
> > 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. Neel
|
Sat, 14 Dec 2002 03:00:00 GMT |
|
 |
r.. #9 / 31
|
 Need help with Class-Allocated Slots
Quote: > > > 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.
There could (ought to) be a way to qualify the ambiguous reference to make it clear which reference is being requested, "method foo" of "slot foo". In the absence of an unambiguous reference the system could simply flag it as an error. In practice, conflicts like this are less of a problem than the lack of having the feature in the first place. Multiple Inheritance can cause conflicts as well, but that doesn't mean it should not be implemented (which is the approach Java took with MI). Dick
|
Sat, 14 Dec 2002 03:00:00 GMT |
|
 |
Bruce Houl #10 / 31
|
 Need help with Class-Allocated Slots
Quote:
> There could (ought to) be a way to qualify the ambiguous reference to > make it clear which reference is being requested, "method foo" of "slot > foo".
No. In Dylan there is no difference between "method foo" and "slot foo". *All* slots are conceptually used via accessor methods, all the time. The compiler creates default accessor methods for slots which read/write memory at the appropriate offset for objects of that class. Different classes might have the same slot at different offsets, because of multiple inheritance. This is handled using Generic Function dispatch to select the correct accessor method for a particular object. If the exact object type is known then the correct method is called directly, or (more usually) inlined into a simple memory reference. The programmer can override the accessor methods for a slot to do something different. You can even have slots with no storage at all ("virtual slots"). -- Bruce
|
Sun, 15 Dec 2002 03:00:00 GMT |
|
 |
Neel Krishnaswa #11 / 31
|
 Need help with Class-Allocated Slots
Quote:
> > 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. [...] > There could (ought to) be a way to qualify the ambiguous reference > to make it clear which reference is being requested, "method foo" of > "slot foo". In the absence of an unambiguous reference the system > could simply flag it as an error.
I'm not so sure of this, actually. The unification of slot access and method dispatch is one of the most elegant features of Dylan, and I'd hate to see it break without a really good rationale. IMO, this is the sort of thing that should either be part of a full-fledged MOP or not present at all. Quote: > In practice, conflicts like this are less of a problem than the lack of > having the feature in the first place. Multiple Inheritance can cause > conflicts as well, but that doesn't mean it should not be implemented > (which is the approach Java took with MI).
In this case, I think that if you need to access class slots before there are instances, you should use a module variable, like: define variable *bar* = 9; define method bar(obj :: <foo>) => (value) *bar* end method; define method bar-setter(value, obj :: <foo>) => (value) *bar* := value end method; Then if you need the bare "class slot", you can access the variable directly. If all this seems kind of grotty to you, then a little macrology can make all the dirt go away: define macro class-slot-definer {define class-slot (?class:name, ?:name) as ?:expression} => {define variable "*!*" ## ?name ## "*!*" = ?expression; define method ?name (obj :: ?class) => (value) "*!*" ## ?name ## "*!*" end method; define method ?name ## "-setter" (value, obj :: ?class) => (value) "*!*" ## ?name ## "*!*" := value; end method; define method class-slot(class :: subclass(?class), gf == ?name) "*!*" ## ?name ## "*!*" end method; define method class-slot-setter(value, class :: subclass(?class), gf == ?name) => (value) "*!*" ## ?name ## "*!*" := value; end method class-slot-setter;} end macro; Use it like this: define class <foo> (<object>) end class <foo>; define class-slot(<foo>, bar) as 10; define method main(appname, #rest arguments) local method test(heading, val-1, val-2) format-out(heading); format-out("\n"); format-out(" x.bar is %=\n", val-1); format-out(" class-slot(<foo>, bar) is %=\n", val-2); end method test; let x = make(<foo>); test("define class-slot(<foo>, bar) as 10;", x.bar, class-slot(<foo>, bar)); x.bar := 15; test("x.bar := 15;", x.bar, class-slot(<foo>, bar)); class-slot(<foo>, bar) := 21; test("class-slot(<foo>, bar) := 21;", x.bar, class-slot(<foo>, bar)); end method main; Which should output something like: define class-slot(<foo>, bar) as 10; x.bar is 10 class-slot(<foo>, bar) is 10 x.bar := 15; x.bar is 15 class-slot(<foo>, bar) is 15 class-slot(<foo>, bar) := 21; x.bar is 21 class-slot(<foo>, bar) is 21 This should pretty much serve your needs, without getting into the strange territory. (Addition of stuff to deal with type declarations, each-subclass slots, and so on are left as an exercise for the reader. :) Neel
|
Sun, 15 Dec 2002 03:00:00 GMT |
|
 |
r.. #12 / 31
|
 Need help with Class-Allocated Slots
As common as class-slots are (at least in the programming I have done), I would still prefer a more direct and less cumbersome method. I would not be content having to use the method you suggest every time I need a class slot. Quote:
> > > 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. [...] > > There could (ought to) be a way to qualify the ambiguous reference > > to make it clear which reference is being requested, "method foo" of > > "slot foo". In the absence of an unambiguous reference the system > > could simply flag it as an error. > I'm not so sure of this, actually. The unification of slot access and > method dispatch is one of the most elegant features of Dylan, and I'd > hate to see it break without a really good rationale. IMO, this is the > sort of thing that should either be part of a full-fledged MOP or not > present at all. > > In practice, conflicts like this are less of a problem than the lack of > > having the feature in the first place. Multiple Inheritance can cause > > conflicts as well, but that doesn't mean it should not be implemented > > (which is the approach Java took with MI). > In this case, I think that if you need to access class slots before > there are instances, you should use a module variable, like: > define variable *bar* = 9; > define method bar(obj :: <foo>) => (value) > *bar* > end method; > define method bar-setter(value, obj :: <foo>) => (value) > *bar* := value > end method; > Then if you need the bare "class slot", you can access the variable > directly. If all this seems kind of grotty to you, then a little > macrology can make all the dirt go away: > define macro class-slot-definer > {define class-slot (?class:name, ?:name) as ?:expression} > => {define variable "*!*" ## ?name ## "*!*" = ?expression; > define method ?name (obj :: ?class) => (value) > "*!*" ## ?name ## "*!*" > end method; > define method ?name ## "-setter" (value, obj :: ?class) => (value) > "*!*" ## ?name ## "*!*" := value; > end method; > define method class-slot(class :: subclass(?class), gf == ?name) > "*!*" ## ?name ## "*!*" > end method; > define method class-slot-setter(value, > class :: subclass(?class), > gf == ?name) => (value) > "*!*" ## ?name ## "*!*" := value; > end method class-slot-setter;} > end macro; > Use it like this: > define class <foo> (<object>) > end class <foo>; > define class-slot(<foo>, bar) as 10; > define method main(appname, #rest arguments) > local method test(heading, val-1, val-2) > format-out(heading); > format-out("\n"); > format-out(" x.bar is %=\n", val-1); > format-out(" class-slot(<foo>, bar) is %=\n", val-2); > end method test; > let x = make(<foo>); > test("define class-slot(<foo>, bar) as 10;", > x.bar, class-slot(<foo>, bar)); > x.bar := 15; > test("x.bar := 15;", > x.bar, class-slot(<foo>, bar)); > class-slot(<foo>, bar) := 21; > test("class-slot(<foo>, bar) := 21;", > x.bar, class-slot(<foo>, bar)); > end method main; > Which should output something like: > define class-slot(<foo>, bar) as 10; > x.bar is 10 > class-slot(<foo>, bar) is 10 > x.bar := 15; > x.bar is 15 > class-slot(<foo>, bar) is 15 > class-slot(<foo>, bar) := 21; > x.bar is 21 > class-slot(<foo>, bar) is 21 > This should pretty much serve your needs, without getting into the > strange territory. (Addition of stuff to deal with type declarations, > each-subclass slots, and so on are left as an exercise for the > reader. :) > Neel
|
Sun, 15 Dec 2002 03:00:00 GMT |
|
 |
Hugh Green #13 / 31
|
 Need help with Class-Allocated Slots
Quote:
> > > 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
|
Sun, 15 Dec 2002 03:00:00 GMT |
|
 |
Scott McKa #14 / 31
|
 Need help with Class-Allocated Slots
Quote:
>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.
I'm not convinced that overriding a class slot with an instance slot should be allowed. A superclass has already effectively declared the protocol -- the slot is class-allocated. Why should a subclass be allowed to break the protocol? Right now, for example, a subclass can't change the type of an inherited slot. Quote: >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.
Data stored in a class slot can't be GC'ed now until the class itself is GC'ed, right? And the class itself can't be GC'ed until you can prove that nobody will ever call 'make' on the class again.
|
Sun, 15 Dec 2002 03:00:00 GMT |
|
 |
Hugh Green #15 / 31
|
 Need help with Class-Allocated Slots
Quote:
> >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. > I'm not convinced that overriding a class slot with an instance slot > should be allowed. A superclass has already effectively declared > the protocol -- the slot is class-allocated. Why should a subclass > be allowed to break the protocol? Right now, for example, a subclass > can't change the type of an inherited slot.
I'm *not* saying you should be able to override a class slot with an instance slot. (I can imagine there being a workable model for that but I don't think it's useful or desirable.) What I am saying is that you can already add specialised accessor methods for subclasses which can do whatever they like, including: *effectively* change the allocation by accessing a hash table or new instance slot or a random number generator or something; printing a debug message, then doing whatever the superclass does; not terminating when called. So ... Being able to override slot accessors in subclasses is *very* useful and shouldn't be prevented. But if we allow it, we can't feasibly stop people doing broken things with it. (We can prevent -- indeed, can't avoid preventing -- some broken things, like changing the type signature; but not everything.) We could, however, illustrate "best practice" and persuade people to do that. In this case, if you want to mess with allocation in subclasses but want a default of "class", the best way is probably to have a superclass "virtual" slot and a subclasses which implements this in terms of a class slot (plus any other subclasses you want, implementing it however you want). (Okay, we *could* theoretically enforce the behaviour of class or each-subclass allocation by having descriptions of invariants to check for all instances, every time you access such a slot, but that's not feasible!) Quote: > >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. > >... > Data stored in a class slot can't be GC'ed now until the class itself > is GC'ed, right?
Well, all the DRM says (in the one place I looked -- it's infamous for having relevant information spread across several separate pages!) is class allocation specifies there is only one storage location used by all the general instances of the class. All the instances share a single value for the slot. If the value is changed in one instance, all the instances see the new value. I *think* there's no value for the slot until the first (successful) call to "make". (At the moment we can't tell. If we make such slots accessible via classes, presumably they have to be initialised whenever the class is "ready", even if no instances exist?) It's not clear (to me, from the above) whether or not the value could be GCd at any point where all instances have been GCd. To put it another way, I think you could GC it and not be inconsistent with the DRM. (Another bit of under-specification in the same area: it seems to me that constant class and each-subclass slots with init-keywords can in fact have their value changed each time "make" is called, because init-values are inserted by some method other than calling the setters.) Quote: > ... And the class itself can't be GC'ed until you can > prove that nobody will ever call 'make' on the class again.
Classes created with "make(<class>, ...)" might become unreachable at some point and hence get GCd. Not common practice, but possible. Sad thing is, I actually *like* all this twisty language stuff :-) Hugh
|
Sun, 15 Dec 2002 03:00:00 GMT |
|
|
Page 1 of 3
|
[ 31 post ] |
|
Go to page:
[1]
[2] [3] |
|