Hi all.
What would people's reaction be if a class was prevented from being able to directly access its superclass's instance variables? A subclass should use accessor methods to access a superclass's instance variables.
Is there any particular reason subclasses get access to superclass instance variables? I think it breaks encapsulation.
If this was implemented, it might be possible to avoid needing to recompile every subclass when you modify the instance variables of a class.
Gulik.
2008/11/25 Michael van der Gulik mikevdg@gmail.com:
Hi all.
What would people's reaction be if a class was prevented from being able to directly access its superclass's instance variables? A subclass should use accessor methods to access a superclass's instance variables.
Is there any particular reason subclasses get access to superclass instance variables? I think it breaks encapsulation.
If this was implemented, it might be possible to avoid needing to recompile every subclass when you modify the instance variables of a class.
No, you can't avoid recompiling. Suppose base class having vars: 0 - a 1 - b
and subclass
2 - d 3 - c
now, if you add or remove vars in base class, indexes of 'd' and 'c' variables will be shifted correspondingly. And therefore it would require to recompile all methods where you using 'd' and 'c' ivars. It also may require recompiling methods in base class, when you inserting a var before a or b.. or removing var 'a'. - for same reason - indexes will be shifted.
Gulik.
-- http://people.squeakfoundation.org/person/mikevdg http://gulik.pbwiki.com/
On Tue, Nov 25, 2008 at 11:40 PM, Igor Stasenko siguctua@gmail.com wrote:
2008/11/25 Michael van der Gulik mikevdg@gmail.com:
Hi all.
What would people's reaction be if a class was prevented from being able
to
directly access its superclass's instance variables? A subclass should
use
accessor methods to access a superclass's instance variables.
Is there any particular reason subclasses get access to superclass
instance
variables? I think it breaks encapsulation.
If this was implemented, it might be possible to avoid needing to
recompile
every subclass when you modify the instance variables of a class.
No, you can't avoid recompiling. Suppose base class having vars: 0 - a 1 - b
and subclass
2 - d 3 - c
now, if you add or remove vars in base class, indexes of 'd' and 'c' variables will be shifted correspondingly. And therefore it would require to recompile all methods where you using 'd' and 'c' ivars. It also may require recompiling methods in base class, when you inserting a var before a or b.. or removing var 'a'. - for same reason - indexes will be shifted.
I was thinking, briefly, about modifying the VM and object memory format so that instance variables are always indexed beginning from 0 for every subclass. Somehow.
It isn't necessarily a good idea. I haven't thought through the details yet.
Gulik.
2008/11/25 Michael van der Gulik mikevdg@gmail.com:
On Tue, Nov 25, 2008 at 11:40 PM, Igor Stasenko siguctua@gmail.com wrote:
2008/11/25 Michael van der Gulik mikevdg@gmail.com:
Hi all.
What would people's reaction be if a class was prevented from being able to directly access its superclass's instance variables? A subclass should use accessor methods to access a superclass's instance variables.
Is there any particular reason subclasses get access to superclass instance variables? I think it breaks encapsulation.
If this was implemented, it might be possible to avoid needing to recompile every subclass when you modify the instance variables of a class.
No, you can't avoid recompiling. Suppose base class having vars: 0 - a 1 - b
and subclass
2 - d 3 - c
now, if you add or remove vars in base class, indexes of 'd' and 'c' variables will be shifted correspondingly. And therefore it would require to recompile all methods where you using 'd' and 'c' ivars. It also may require recompiling methods in base class, when you inserting a var before a or b.. or removing var 'a'. - for same reason - indexes will be shifted.
I was thinking, briefly, about modifying the VM and object memory format so that instance variables are always indexed beginning from 0 for every subclass. Somehow.
Well, if you put ivars into dictionary of some sort, then you don't need to recompile anything. But speed tradeoff will be huge :) One possible format change could be to keep a class ivars starting index in its instanceFormat field. Then, when you changing the number of ivars, you simply go through subclasses and update their instanceFormat w/o recompiling methods. You still need to recompile methods but only of class which changes its ivars:
ClassA (ivarsIndex = 0) ivars: a, b, c
ClassB (ivarsIndex = 3) ivars: d,e,f
Now if you change ClassA ivars to = 'b,c' you setting ClassB ivarsIndex = 2 and recompiling ClassA methods.
An ivar accessing instruction now requires 2 arguments: index and class.
ivarAddr = oop at: (class ivarsIndex) + index
not much overhead, but you have to keep a class oop in literal frame of method :
ClassB >> methodFoo ^ a + e
will require to keep 2 class oops (ClassA and ClassB) , because you accessing ivars from both of them..
IMO, it is better to recompile things all the way down, rather than bother with such complexity which gives no real benefits except compiling time.
It isn't necessarily a good idea. I haven't thought through the details yet.
Gulik.
-- http://people.squeakfoundation.org/person/mikevdg http://gulik.pbwiki.com/
On Wed, Nov 26, 2008 at 12:13:14AM +0200, Igor Stasenko wrote:
IMO, it is better to recompile things all the way down, rather than bother with such complexity which gives no real benefits except compiling time.
Or switch to SystemEditor, which can recompile classes 6-8x faster than ClassBuilder.
Matthew Fulmer wrote:
On Wed, Nov 26, 2008 at 12:13:14AM +0200, Igor Stasenko wrote:
IMO, it is better to recompile things all the way down, rather than bother with such complexity which gives no real benefits except compiling time.
Or switch to SystemEditor, which can recompile classes 6-8x faster than ClassBuilder.
Really? I'm somewhat surprised to hear that. It means that either most of the time in recompilation doesn't go where I think it goes or that SystemEditor does things very differently from ClassBuilder. Either way I always take a 6x-8x speedup when I can get one - where do I find SystemEditor to run a few benchmarks against it?
Cheers, - Andreas
On Tue, Nov 25, 2008 at 03:45:09PM -0800, Andreas Raab wrote:
Matthew Fulmer wrote:
On Wed, Nov 26, 2008 at 12:13:14AM +0200, Igor Stasenko wrote:
IMO, it is better to recompile things all the way down, rather than bother with such complexity which gives no real benefits except compiling time.
Or switch to SystemEditor, which can recompile classes 6-8x faster than ClassBuilder.
Really? I'm somewhat surprised to hear that. It means that either most of the time in recompilation doesn't go where I think it goes or that SystemEditor does things very differently from ClassBuilder. Either way I always take a 6x-8x speedup when I can get one - where do I find SystemEditor to run a few benchmarks against it?
Most of the time recompiling a class is not in the compiler. It is in the three full image scans necessary to swap all object instances. All three are within ClassBuilder >> update:to:
1. allInstances in ClassDescription >> updateInstancesFrom: 2. elementsExchangeIdentityWith: in ClassDescription >> updateInstancesFrom:to:isMeta: 3. becomeForward: or elementsForwardIdentityTo: in ClassBuilder >> update:to:
ClassBuilder thus does 3n full memory scans (where n is the number of classes to recompile)
SystemEditor does n + 2 full memory scans. It does the allInstances search once per class, then groups all the becomes into two becomes at the end of the commit (which is most of the reason why SystemEditor is truly atomic). I've tried to collapse the n allInstance scans into one, but have been unable so far to do it without crashing the VM. I think one should be able to compile any number of classes with just two memory scans (one to find all instances, one to becomeForward: them)
The best way to benchmark SystemEditor is to get Monticello 1.6, which is already hooked up to use SystemEditor for all its loading needs. Run the following to get MC1.6:
HttpSocket httpFileIn: 'installer.pbwiki.org/f/mc15.st'. Installer install: 'Monticello16-Beta'
Beware: SystemEditor cannot yet handle packages with Traits or packages that have Tweak classes. I'm working on it.
For some more info on SystemEditor, see http://installer.pbwiki.org/SystemEditor http://installer.pbwiki.org/Monticello16-Beta
I havn't put any SystemEditor speed data on the wiki yet. They'll be more documentation as I push to get Monticello 1.6 into a final release, which should be in about two months
Matthew Fulmer wrote:
Most of the time recompiling a class is not in the compiler. It is in the three full image scans necessary to swap all object instances. All three are within ClassBuilder >> update:to:
That assumes that the majority of time being spent in class reshapes is spent in these memory scans. This certainly didn't used to be the case - the majority of time when dealing with real class hierarchies like Morphic or MVC was spent recompiling (i.e., parsing). Since the compiler is still the same I'm surprised you see that much of a speedup. Unless SystemEditor doesn't recompile but rather relink (update ivar mapping only without parsing)? This would certainly give it a serious boost.
- allInstances in ClassDescription >> updateInstancesFrom:
- elementsExchangeIdentityWith: in ClassDescription >> updateInstancesFrom:to:isMeta:
- becomeForward: or elementsForwardIdentityTo: in ClassBuilder >> update:to:
ClassBuilder thus does 3n full memory scans (where n is the number of classes to recompile)
Yes. Partly to preserve space (since you only need to deal with all the instance of a single class instead of an entire class hierarchy like Morphic). The other reason is ... ClassBuilder>>update:to: which is one nasty set of constraints that it's hard to believe (and even harder to get right).
SystemEditor does n + 2 full memory scans. It does the allInstances search once per class, then groups all the becomes into two becomes at the end of the commit (which is most of the reason why SystemEditor is truly atomic). I've tried to collapse the n allInstance scans into one, but have been unable so far to do it without crashing the VM. I think one should be able to compile any number of classes with just two memory scans (one to find all instances, one to becomeForward: them)
Holy cow. If that actually works, it's impressive as hell. Given the complexity in ClassBuilder (all of which is the direct result of people actually using it and running into issues) it'll be no small feat to get this right in SystemEditor. I've spent a few years on it ;-)
I'm looking forward to test-drive SystemEditor a little more.
Cheers, - Andreas
On 25-Nov-08, at 11:21 PM, Andreas Raab wrote:
Holy cow. If that actually works, it's impressive as hell. Given the complexity in ClassBuilder (all of which is the direct result of people actually using it and running into issues) it'll be no small feat to get this right in SystemEditor. I've spent a few years on it ;-)
It shows. ClassBuilder isn't actually that hard to understand. The constraints are hairy, but the code is fairly straightforward and has lots of comments.
In SystemEditor, those constraints are encapsulated in ClassFormat, with unit tests. The tests probably aren't as complete as they could be, but it gives us a place to document issues as they come up.
I'm looking forward to reenabling atomic commits in Monticello2. The speed improvement there is even greater, because right now, MC2 takes a speed hit from loading instance variables one at a time.
Colin
Hi Colin -
I was looking over SystemEditor and one thing that really surprised me was the use of ClassEditors as proxies. What is the reasoning behind it? It makes the design difficult to understand and extremely hard to debug - I gave up trying to find out what causes the issue with class migration when I effectively couldn't debug the editors since all they would show me were those pretend-classes. Is there some sort of debug mode to turn off all that evil magic? ;-)
Cheers, - Andreas
Colin Putney wrote:
On 25-Nov-08, at 11:21 PM, Andreas Raab wrote:
Holy cow. If that actually works, it's impressive as hell. Given the complexity in ClassBuilder (all of which is the direct result of people actually using it and running into issues) it'll be no small feat to get this right in SystemEditor. I've spent a few years on it ;-)
It shows. ClassBuilder isn't actually that hard to understand. The constraints are hairy, but the code is fairly straightforward and has lots of comments.
In SystemEditor, those constraints are encapsulated in ClassFormat, with unit tests. The tests probably aren't as complete as they could be, but it gives us a place to document issues as they come up.
I'm looking forward to reenabling atomic commits in Monticello2. The speed improvement there is even greater, because right now, MC2 takes a speed hit from loading instance variables one at a time.
Colin
On Wed, Nov 26, 2008 at 02:53:17PM -0800, Andreas Raab wrote:
Hi Colin -
I was looking over SystemEditor and one thing that really surprised me was the use of ClassEditors as proxies. What is the reasoning behind it? It makes the design difficult to understand and extremely hard to debug
- I gave up trying to find out what causes the issue with class
migration when I effectively couldn't debug the editors since all they would show me were those pretend-classes. Is there some sort of debug mode to turn off all that evil magic? ;-)
yes. from the context of a class editor, do this:
self system debug: true
I got fed up with that myself today and made debug mode the default. I havn't committed that change yet.
The problem with migration is most likely in InstanceMigrator. I'm looking into that myself. It is a new bug. This used to work.
On Wed, Nov 26, 2008 at 03:59:48PM -0700, Matthew Fulmer wrote:
On Wed, Nov 26, 2008 at 02:53:17PM -0800, Andreas Raab wrote:
Hi Colin -
I was looking over SystemEditor and one thing that really surprised me was the use of ClassEditors as proxies. What is the reasoning behind it? It makes the design difficult to understand and extremely hard to debug
- I gave up trying to find out what causes the issue with class
migration when I effectively couldn't debug the editors since all they would show me were those pretend-classes. Is there some sort of debug mode to turn off all that evil magic? ;-)
yes. from the context of a class editor, do this:
self system debug: true
I got fed up with that myself today and made debug mode the default. I havn't committed that change yet.
Committed: SystemEditor-Squeak-mtf.160
The problem with migration is most likely in InstanceMigrator. I'm looking into that myself. It is a new bug. This used to work.
-- Matthew Fulmer -- http://mtfulmer.wordpress.com/
Matthew Fulmer wrote:
self system debug: true
I got fed up with that myself today and made debug mode the default. I havn't committed that change yet.
Committed: SystemEditor-Squeak-mtf.160
After loading that version and executing:
ed := SystemEditor new. (ed at: #SimpleButtonMorph) addInstVarName: #foo. ed commitWithProgress.
nothing at all happens, e.g., no variable gets added to SimpleButtonMorph (this is in 3.10.7159 in case it matters). The same for mtf.161 which I tried as well.
Is there something resembling a "stable" version of SystemEditor that I can use to try some of the harder tasks on? The experience so far is a bit unsatisfying given that SE doesn't execute basic tasks correctly.
Cheers, - Andreas
Okay, I'm slowly getting there. It seems like updating SystemEditor in MC in 3.10 somehow broke it - some methods were simply referring to the wrong ivars which caused SE not to work at all. Recompiling the SE packages fixed that.
Secondly, the issue I was seeing with the iVars being incorrect are one of the subtleties that SE currently doesn't correctly deal with. Here is an illustration:
testCleanupOfOldInstances "Ensure that old instance are cleaned up properly" instance := CleanupTestClass new. Smalltalk garbageCollect. "for easier results make it old"
self assert: CleanupTestClass instanceCount = 1.
ed := SystemEditor new. (ed at: #CleanupTestClass) addInstVarName: #whatever. ed commit.
self assert: CleanupTestClass instanceCount = 1.
ed := SystemEditor new. (ed at: #CleanupTestClass) removeInstVarName: #whatever. ed commit.
self assert: CleanupTestClass instanceCount = 1.
The problem is that since #become: changes class pointers you *must* clean out the old instances or otherwise they'll be completely and utterly broken when you finally #become: the classes itself. This can be achieved by placing a strategic full GC in the right place in the migration process (I'm not sure where that would be in SE but probably somewhere in the migration transaction).
Cheers, - Andreas
On Wed, Nov 26, 2008 at 07:45:14PM -0800, Andreas Raab wrote:
Secondly, the issue I was seeing with the iVars being incorrect are one of the subtleties that SE currently doesn't correctly deal with. Here is an illustration:
testCleanupOfOldInstances "Ensure that old instance are cleaned up properly" instance := CleanupTestClass new. Smalltalk garbageCollect. "for easier results make it old"
self assert: CleanupTestClass instanceCount = 1.
ed := SystemEditor new. (ed at: #CleanupTestClass) addInstVarName: #whatever. ed commit.
self assert: CleanupTestClass instanceCount = 1.
ed := SystemEditor new. (ed at: #CleanupTestClass) removeInstVarName: #whatever. ed commit.
self assert: CleanupTestClass instanceCount = 1.
The problem is that since #become: changes class pointers you *must* clean out the old instances or otherwise they'll be completely and utterly broken when you finally #become: the classes itself. This can be achieved by placing a strategic full GC in the right place in the migration process (I'm not sure where that would be in SE but probably somewhere in the migration transaction).
You are right. There is no equivalant to the garbageCollect in ClassBuilder >> migrate:to:. The best place to put it would probably be at the end of SystemEditor>>commit
On Sat, Nov 29, 2008 at 08:26:24PM -0700, Matthew Fulmer wrote:
You are right. There is no equivalant to the garbageCollect in ClassBuilder >> migrate:to:. The best place to put it would probably be at the end of SystemEditor>>commit
fixed in 262. thanks.
On 26-Nov-08, at 2:53 PM, Andreas Raab andreas.raab@gmx.de wrote:
Hi Colin -
I was looking over SystemEditor and one thing that really surprised me was the use of ClassEditors as proxies. What is the reasoning behind it? It makes the design difficult to understand and extremely hard to debug - I gave up trying to find out what causes the issue with class migration when I effectively couldn't debug the editors since all they would show me were those pretend-classes. Is there some sort of debug mode to turn off all that evil magic? ;-)
The purpose of SystemEditor is to provide a way to atomically apply changes to the system, using an interface identical to the reflective interface already in use. The proxies provide protocol compatibility, while recording the changes, that need to be made. Then, when it's time to commit, it does all the class building, compiling, instance migration and so on, and finally installs it atomically with a mass become.
So the design is aimed at providing easy-to-adopt atomic updates. The increase in performance is icing, but it makes sense, I guess. Making a change involves a certain amount of overhead, and making the changes one by one incurs that overhead for each change. SystemEditor aggregates changes and can amortize the overhead across several changes. Monticello 2 benefits from this even more than Monticello1, because it deals with instance variables individually, and so incurs migration overhead for each ivar, rather than for each class.
I hear you though. If you think ClassEditor is evil, look at MetaclassEditor. ;-)
Colin
Colin Putney wrote:
The purpose of SystemEditor is to provide a way to atomically apply changes to the system, using an interface identical to the reflective interface already in use. The proxies provide protocol compatibility, while recording the changes, that need to be made.
But why do you need proxying and protocol compatibility? The only reason I've ever found was to make sure existing tools (browser etc) can work with those proxies. Is this what you're after, e.g., have a browser with a "commit" button which then does all the changes atomically? If not, I'm not sure what you need the proxying / protocol compatibility for.
I hear you though. If you think ClassEditor is evil, look at MetaclassEditor. ;-)
Heh. I knew what I was in for when ClassEditor class>>new said something along the lines of "MetaclassEditor new new" ;-)
Cheers, - Andreas
On 27-Nov-08, at 1:28 AM, Andreas Raab wrote:
But why do you need proxying and protocol compatibility? The only reason I've ever found was to make sure existing tools (browser etc) can work with those proxies. Is this what you're after, e.g., have a browser with a "commit" button which then does all the changes atomically? If not, I'm not sure what you need the proxying / protocol compatibility for.
Well, yeah. My immediate goal was atomic loads for MC2, which was already working non-atomically using the existing protocol. It wasn't completely trivial to make MC2 use SystemEditor, but it was pretty easy. Now that the work has been done, turning atomic loading on or off is a one line change. It could be a preference.
But beyond that, the barrier to adoption to these sorts of things is always tool support. The browser is actually the least interesting tool in this case, since it makes one change at a time, and you usually want them applied immediately anyway. It might be useful for especially fiddly stuff like hacking on Compiler, but that's pretty rare. I was actually more interested in tools that load code in bulk: MC1, MC2, file-in, SAR, SqueakMap etc.
The alternative would have been a protocol with methods like #classNamed:addInstVar:, written as part of MC2 rather than as an independent package. That could still work, if compatibility turns out to be more trouble than it's worth.
Colin
Colin, Matthew and Andreas.
Can I beg doing a swiki page about SystemEditor , with all you was discussing here ?
Tutorials ?
I waiting from Ralph times before the end of 3.10 this important tool was finished.
Seems the long wait is near to end , congrats to all :=)
Edgar
Andreas Raab wrote:
Matthew Fulmer wrote:
On Wed, Nov 26, 2008 at 12:13:14AM +0200, Igor Stasenko wrote:
IMO, it is better to recompile things all the way down, rather than bother with such complexity which gives no real benefits except compiling time.
Or switch to SystemEditor, which can recompile classes 6-8x faster than ClassBuilder.
Really? I'm somewhat surprised to hear that. It means that either most of the time in recompilation doesn't go where I think it goes or that SystemEditor does things very differently from ClassBuilder. Either way I always take a 6x-8x speedup when I can get one - where do I find SystemEditor to run a few benchmarks against it?
Cheers,
- Andreas
Installer squeaksource project: 'SystemEditor'; install: 'SystemEditor-Core'; install: 'SystemEditor-Squeak'.
http://installer.pbwiki.com/SystemEditor
I just added it to the development package universe, along with Monticello15 and Monticello16. MC1.6 uses SystemEditor and I love it!
Keith
Keith Hodges wrote:
Installer squeaksource project: 'SystemEditor'; install: 'SystemEditor-Core'; install: 'SystemEditor-Squeak'.
http://installer.pbwiki.com/SystemEditor
I just added it to the development package universe, along with Monticello15 and Monticello16. MC1.6 uses SystemEditor and I love it!
Thanks. And do you by any chance have a simple example, say adding an iVar to an existing class?
Cheers, - Andreas
On Tue, Nov 25, 2008 at 10:47:12PM -0800, Andreas Raab wrote:
Keith Hodges wrote:
Installer squeaksource project: 'SystemEditor'; install: 'SystemEditor-Core'; install: 'SystemEditor-Squeak'.
http://installer.pbwiki.com/SystemEditor
I just added it to the development package universe, along with Monticello15 and Monticello16. MC1.6 uses SystemEditor and I love it!
Thanks. And do you by any chance have a simple example, say adding an iVar to an existing class?
The syntax to do that is:
ed := SystemEditor new. (ed at: #Morph) addInstVarName: #foo. ed commitWithProgress.
Adding an instance variable to Morph used to work, but now it runs out of memory :P
Matthew Fulmer wrote:
The syntax to do that is:
ed := SystemEditor new. (ed at: #Morph) addInstVarName: #foo. ed commitWithProgress.
Adding an instance variable to Morph used to work, but now it runs out of memory :P
This doesn't seem to work. If I do something a little simpler:
ed := SystemEditor new. (ed at: #SimpleButtonMorph) addInstVarName: #foo. ed commitWithProgress.
it completes but subinstances of SimpleButtonMorph are not correctly migrated. Try inspecting foo in "IconicButton someInstance" or in "UpdatingSimpleButtonMorph someInstance".
Cheers, - Andreas
On Wed, Nov 26, 2008 at 09:06:16AM -0800, Andreas Raab wrote:
Matthew Fulmer wrote:
The syntax to do that is:
ed := SystemEditor new. (ed at: #Morph) addInstVarName: #foo. ed commitWithProgress.
Adding an instance variable to Morph used to work, but now it runs out of memory :P
This doesn't seem to work. If I do something a little simpler:
ed := SystemEditor new. (ed at: #SimpleButtonMorph) addInstVarName: #foo. ed commitWithProgress.
it completes but subinstances of SimpleButtonMorph are not correctly migrated. Try inspecting foo in "IconicButton someInstance" or in "UpdatingSimpleButtonMorph someInstance".
I don't see any incorrect migration of the ivar layout, but I did find out that the methods aren't being recompiled. I fixed this in 161.
Michael van der Gulik wrote:
I was thinking, briefly, about modifying the VM and object memory format so that instance variables are always indexed beginning from 0 for every subclass. Somehow.
See a detailed implementation of this here -
http://stephane.ducasse.free.fr/FreeBooks/LittleSmalltalk/ALittleSmallta lk.pdf
It isn't necessarily a good idea. I haven't thought through the details yet.
I think that the versions of Little Smalltalk created after the book was published no longer use this idea. I would have to look at the sources again to be sure.
-- Jecel
Joshua Gargus wrote:
Craig Latta wrote:
What would people's reaction be if a class was prevented from being able to directly access its superclass's instance variables?
"This is insane." :)
"I hope you have a good inlining JIT" :-p
It's neither insane nor is an inlining JIT is a strict necessity. Tweak for example uses property dictionaries throughout and although it's slower than I'd like it to be it's certainly acceptable for most situations. Also, doesn't Newspeak use messages for *all* accessors?
I think most people would be surprised to see how acceptable the practical behavior is on modern day machines. The boxes are so darn fast it's not even funny...
Cheers, - Andreas
Oh, I wasn't even thinking of the performance implications. I think it's a bad idea from a semantic standpoint, too. And I'm not saying that property dictionaries are necessarily bad (although I sure haven't enjoyed the implications for debugging and navigating unfamiliar code so far!).
-C
Heh, sorry to use the mailing list like IRC. :)
What seems particularly weird to me is using direct access for some instance variables but not others (which is what I sensed from Michael's original message). Of course there are reasonable systems that don't have direct access at all.
-C
On Tue, Nov 25, 2008 at 3:48 PM, Andreas Raab andreas.raab@gmx.de wrote:
It's neither insane nor is an inlining JIT is a strict necessity. Tweak for example uses property dictionaries throughout and although it's slower than I'd like it to be it's certainly acceptable for most situations. Also, doesn't Newspeak use messages for *all* accessors?
Yes, it does, and it's very nice especially considering that classes are mixins, and inst var index base is different in different mixin applications.
--Vassili
2008/11/26 Vassili Bykov smalltalkbigot@gmail.com:
On Tue, Nov 25, 2008 at 3:48 PM, Andreas Raab andreas.raab@gmx.de wrote:
It's neither insane nor is an inlining JIT is a strict necessity. Tweak for example uses property dictionaries throughout and although it's slower than I'd like it to be it's certainly acceptable for most situations. Also, doesn't Newspeak use messages for *all* accessors?
Yes, it does, and it's very nice especially considering that classes are mixins, and inst var index base is different in different mixin applications.
I like the idea of hiding the state/storage specific details from eyes of subclasses. It makes irrelevant, in what format or where particular object holds its state. As long as you providing messages to access it, it could be anything.
--Vassili
On 25-Nov-2008, at 7:57 PM, Igor Stasenko wrote:
I like the idea of hiding the state/storage specific details from eyes of subclasses. It makes irrelevant, in what format or where particular object holds its state. As long as you providing messages to access it, it could be anything.
So why not just get rid of instance variables completely? :-)
I think Ramon Leon hit the nail on the head. You're not supposed to try to protect anything in a class definition from any of its subclasses. Inheritance is a mechanism to _expand_ upon the definition of a class, not restrict it.
An instance of an object contains all of the components (instance variables, methods, etc.) of the class it belongs to as well as, by definition, all of the components from any (and all) class(es) it inherits from. That's the whole idea, as I understand it, underlying the concept of inheritance.
An object shouldn't have to use accessor methods to get at its own internal state, no matter where in the class hierarchy its state may be defined. "super" is only needed to get around explicit re- definitions done by the subclass.
2008/11/26 Greg A. Woods; Planix, Inc. woods@planix.ca:
On 25-Nov-2008, at 7:57 PM, Igor Stasenko wrote:
I like the idea of hiding the state/storage specific details from eyes of subclasses. It makes irrelevant, in what format or where particular object holds its state. As long as you providing messages to access it, it could be anything.
So why not just get rid of instance variables completely? :-)
I think Ramon Leon hit the nail on the head. You're not supposed to try to protect anything in a class definition from any of its subclasses. Inheritance is a mechanism to _expand_ upon the definition of a class, not restrict it.
An instance of an object contains all of the components (instance variables, methods, etc.) of the class it belongs to as well as, by definition, all of the components from any (and all) class(es) it inherits from. That's the whole idea, as I understand it, underlying the concept of inheritance.
An object shouldn't have to use accessor methods to get at its own internal state, no matter where in the class hierarchy its state may be defined. "super" is only needed to get around explicit re-definitions done by the subclass.
My understanding of inheritance is different, in short: A subclass of particular class is a _specialization_ of base class, not _expansion_.
An instance of subclass provides same interface as base class, but with possibly different behavior (because of overrides) or provide additional specialized interface (by introducing new methods).
If you look from a user's point of view (outside a class), you could only send a messages to it. So, for you, as for user its not relevant where an object holds its state - you only interested in its behavior/interface.
As for subclass - a subclass interested in inheriting same interface as base class. Inheriting a state information having a little importance, its just an implementation detail for outside user of class, because anyways he unable to operate with this state directly.
-- Greg A. Woods; Planix, Inc. woods@planix.ca
On 25-Nov-2008, at 10:45 PM, Igor Stasenko wrote:
My understanding of inheritance is different, in short: A subclass of particular class is a _specialization_ of base class, not _expansion_.
Well when you're defining the behaviour of objects in an OO system there's not really any difference between "specialization" and "expansion" -- the subclass is _adding_ changes to the definitions given in the superclass. Perhaps the changes will over-ride a behaviour in the superclass, or modify it in some way, but fundamentally a subclass is always adding something to the superclass in order to create the new subclass it defines.
Or to paraphrase the Blue Book, allowing intersection in class membership is the basic mechanism used to allow code sharing between class descriptions. Smalltalk-80 of course doesn't allow multiple inheritance, just plain subclassing.
If you look from a user's point of view (outside a class), you could only send a messages to it. So, for you, as for user its not relevant where an object holds its state - you only interested in its behavior/interface.
You don't send messages to a class -- you send messages to objects which are derived from a class, i.e. which follow the behaviours defined by the class.
As for subclass - a subclass interested in inheriting same interface as base class. Inheriting a state information having a little importance, its just an implementation detail for outside user of class, because anyways he unable to operate with this state directly.
Classes don't have state -- objects have state. An object which has been derived from a subclass gains definitions about its state from _all_ of the classes in the class hierarchy which the subclass belongs to.
At least that's how I understand things in the Smalltalk way of defining classes and instantiating objects.
2008/11/26 Greg A. Woods; Planix, Inc. woods@planix.ca:
On 25-Nov-2008, at 10:45 PM, Igor Stasenko wrote:
My understanding of inheritance is different, in short: A subclass of particular class is a _specialization_ of base class, not _expansion_.
Well when you're defining the behaviour of objects in an OO system there's not really any difference between "specialization" and "expansion" -- the subclass is _adding_ changes to the definitions given in the superclass. Perhaps the changes will over-ride a behaviour in the superclass, or modify it in some way, but fundamentally a subclass is always adding something to the superclass in order to create the new subclass it defines.
No, specialization and expansion having really different meanings, if you consider a class, like SmallInteger. Following your understanding, one may want to expand a SmallInteger class by subclassing it and providing additional behavior. Following my understanding, SmallInteger class is highly specialized class, up to the point that its impossible to specialize it further.
Or to paraphrase the Blue Book, allowing intersection in class membership is the basic mechanism used to allow code sharing between class descriptions. Smalltalk-80 of course doesn't allow multiple inheritance, just plain subclassing.
If you look from a user's point of view (outside a class), you could only send a messages to it. So, for you, as for user its not relevant where an object holds its state - you only interested in its behavior/interface.
You don't send messages to a class -- you send messages to objects which are derived from a class, i.e. which follow the behaviours defined by the class.
As for subclass - a subclass interested in inheriting same interface as base class. Inheriting a state information having a little importance, its just an implementation detail for outside user of class, because anyways he unable to operate with this state directly.
Classes don't have state -- objects have state. An object which has been derived from a subclass gains definitions about its state from _all_ of the classes in the class hierarchy which the subclass belongs to.
Of course i know it. Just a small(talk) correction: classes are objects as well and having state as well.
At least that's how I understand things in the Smalltalk way of defining classes and instantiating objects.
From "The Early History of Smalltalk" by Alan Kay
1. Everything is an object 2. Objects communicate by sending and receiving messages (in terms of objects) 3. Objects has their own memory (in terms of objects) ---- 4. Every object is an instance of class (which must be an object) 5. The class holds the shared behavior for its instances (in the form of objects in a program list) 6. To eval a program list, control is passed to the first object and the remainder is treated as its message
so, where in these statements you find anything about inheritance, or something where it says that subclass(es) should have any assumptions about the ways how superclass is storing its instances in memory, and therefore a subclass allowed to directly manipulate the object's state without consulting with superclass?
-- Greg A. Woods; Planix, Inc. woods@planix.ca
On 26.11.2008 05:32, Igor Stasenko wrote:
Of course i know it. Just a small(talk) correction: classes are objects as well and having state as well.
From "The Early History of Smalltalk" by Alan Kay
- Everything is an object
- Objects communicate by sending and receiving messages (in terms of objects)
- Objects has their own memory (in terms of objects)
- Every object is an instance of class (which must be an object)
- The class holds the shared behavior for its instances (in the form
of objects in a program list) 6. To eval a program list, control is passed to the first object and the remainder is treated as its message
so, where in these statements you find anything about inheritance, or something where it says that subclass(es) should have any assumptions about the ways how superclass is storing its instances in memory, and therefore a subclass allowed to directly manipulate the object's state without consulting with superclass?
I'm afraid Alan wasn't as precise as he should have been here. In a Squeak image, everything *IS REPRESENTED* by an object. I represent a cat by an object, but that doesn't magically transform the purring cat into a Squeak object. I *REPRESENT* a class by an object, but it is confusing the issue to remove the distinction between the essence of a class and its representation as an object. Many a discussion has gone astray through this confusion. (Have you ever heard anyone say "class A send a message to class B" when they mean "an instance of class A send a message to an instance of class B"? )
--Trygve
2008/11/26 Trygve Reenskaug trygver@ifi.uio.no:
On 26.11.2008 05:32, Igor Stasenko wrote:
Of course i know it. Just a small(talk) correction: classes are objects as well and having state as well.
From "The Early History of Smalltalk" by Alan Kay
- Everything is an object
- Objects communicate by sending and receiving messages (in terms of
objects) 3. Objects has their own memory (in terms of objects)
- Every object is an instance of class (which must be an object)
- The class holds the shared behavior for its instances (in the form
of objects in a program list) 6. To eval a program list, control is passed to the first object and the remainder is treated as its message
so, where in these statements you find anything about inheritance, or something where it says that subclass(es) should have any assumptions about the ways how superclass is storing its instances in memory, and therefore a subclass allowed to directly manipulate the object's state without consulting with superclass?
I'm afraid Alan wasn't as precise as he should have been here.
I think he did this intentionally, because a precise parts is up to implementation. The principles above is most generic ones. Btw, notice a line between 3 and 4, its not just a random stroke - its actually shows a first step from most generic to more specific.
In a Squeak image, everything *IS REPRESENTED* by an object. I represent a cat by an object, but that doesn't magically transform the purring cat into a Squeak object. I *REPRESENT* a class by an object, but it is confusing the issue to remove the distinction between the essence of a class and its representation as an object. Many a discussion has gone astray through this confusion.
To be fair , i was confused at first time , trying to understand how basic class structure is defined and what connection between Object, Behavior, Class and Metaclass. Still, i wrote a bootstrap code in a few days, and it worked :) Its hard to express such structure in words. But if you doing it step by step - its not that hard.
From VM's point of view: a class is a structure which holds a method
dictionary in one of its slots, so VM could perform method lookup. Yes, its quite special entity, and you can't freely change it. But this not makes it a less object than anything else. Its just another kind of specialization :)
(Have you ever heard anyone say "class A send a message to class B" when they mean "an instance of class A send a message to an instance of class B"? )
Never heard of it. People who saying like this, either don't understand how message passing working , or its just a phrase taken out from context, where everyone understand that speaker having something concrete (instances or class objects themselves) in mind. I can imagine smalltalk without inheritance, and even without classes (in Squeak's form). But not without message passing.
--Trygve
Trygve Reenskaug mailto: trygver@ifi.uio.no
Morgedalsvn. 5A http://heim.ifi.uio.no/~trygver
N-0378 Oslo Tel: (+47) 22 49 57 27
Norway
On 26.11.2008, at 09:48, Igor Stasenko wrote:
2008/11/26 Trygve Reenskaug trygver@ifi.uio.no:
On 26.11.2008 05:32, Igor Stasenko wrote:
- Everything is an object
- Objects communicate by sending and receiving messages (in terms
of objects) 3. Objects has their own memory (in terms of objects)
- Every object is an instance of class (which must be an object)
- The class holds the shared behavior for its instances (in the
form of objects in a program list) 6. To eval a program list, control is passed to the first object and the remainder is treated as its message
so, where in these statements you find anything about inheritance, or something where it says that subclass(es) should have any assumptions about the ways how superclass is storing its instances in memory, and therefore a subclass allowed to directly manipulate the object's state without consulting with superclass?
I'm afraid Alan wasn't as precise as he should have been here.
I think he did this intentionally, because a precise parts is up to implementation. The principles above is most generic ones. Btw, notice a line between 3 and 4, its not just a random stroke - its actually shows a first step from most generic to more specific.
Just a meta remark - I find it highly amusing how people dissect the Gospel of Alan, even interpreting it literally. He must get quite a chuckle from that ;)
- Bert -
(Attention-conservation notice: the penultimate paragraph is most important.)
Bert Freudenberg wrote:
Just a meta remark - I find it highly amusing how people dissect the Gospel of Alan, even interpreting it literally. He must get quite a chuckle from that ;)
Well I hope so! :-)
From reading the old and new papers out there, and the interviews, and
the new stuff VPRI are up to, I'm getting the impression that it's very difficult to understand the *subtlety* of the ideas that led to Smalltalk[1] -- which leads people (like me) to mistakenly concentrate on the artifacts (i.e. Smalltalk) and their properties, when the motivation for constructing the artifacts is much more important.
Smalltalk is much more interesting when viewed as almost a throwaway experiment in realising some of these more abstract background ideas.
Part of the problem, I think, is that the ideas aren't just subtle, they're also *alien* to the vast majority of programmers out there: hobbyists, academics, and those in industry alike. Very hard to get one's head around. (Compare with Dijkstra's opinion of BASIC.)
***** I'd really appreciate an extended essay -- a textbook? a manifesto? -- from those who properly grok it (i.e. Alan and those at VPRI), aimed at helping out those who'd like to: a kind of little-step by little-step introduction to weaning people off their current mindset and helping them explore the subtleties of the new way of looking at things. Something akin in spirit, perhaps, to Drexler's Engines of Creation. *****
It'd be useful not just to me, but for all those I (and no doubt other readers of this list) run across who can't understand why Smalltalk-the-artifact is simultaneously a great improvement on its successors and a system unsuitable for serious use.
Regards, Tony
[1] such as, from http://www.mprove.de/diplom/gui/Kay72a.pdf, the view of the duality between data and function through the lens of process, and from the newer VPRI material the "particles and fields" metaphor of distributed systems.
"Smalltalk-the-artifact is simultaneously a great improvement on its successors and a system unsuitable for serious use."
Eeeek! Don't think I'd go that far.
Smalltalk-the-artifact is certainly suitable for serious work. It's paid my bills a number of times and is still used quite seriously in industry.
David Mitchell wrote:
Smalltalk-the-artifact is certainly suitable for serious work. It's paid my bills a number of times and is still used quite seriously in industry.
Agreed. I was deliberately being pithy. :-) Perhaps I should have said "simultaneously a great improvement on its successors and a flawed system in need of serious revision."
(Plenty of seriously flawed systems get serious use. What intrigues me is considering the reasons why Unix is vastly more popular than Smalltalk -- they're broadly comparable. I think the answer is to do with trust boundaries, shared state, and structured metaprogramming. That's a handwave, of course :-) )
Tony
Tony Garnock-Jones wrote:
Bert Freudenberg wrote:
Just a meta remark - I find it highly amusing how people dissect the Gospel of Alan, even interpreting it literally. He must get quite a chuckle from that ;)
Well I hope so! :-)
Given how happy he said he was to not have any disciples, he might be less than amused to find out otherwise ;-)
Going to the other extreme, where everyone's opinion is equally valid, leads to situations like a guy explaining to me on comp.lang.lisp that multiple dispatch is the most important feature of OOP and so CLOS and C++ are true OO languages but Smalltalk is not.
http://groups.google.com/group/comp.lang.lisp/browse_thread/thread/b2aa1842c...
-- Jecel
El 11/26/08 2:53 PM, "Tony Garnock-Jones" tonyg@lshift.net escribió:
***** I'd really appreciate an extended essay -- a textbook? a manifesto? -- from those who properly grok it (i.e. Alan and those at VPRI), aimed at helping out those who'd like to: a kind of little-step by little-step introduction to weaning people off their current mindset and helping them explore the subtleties of the new way of looking at things. Something akin in spirit, perhaps, to Drexler's Engines of Creation. *****
Then you should look material of Alejandro Reimondo . He is talking and writing about Objects and "Beyond Objects" (perdon Ale) all this years. He have his group for discuss "Alejandro F. Reimondo" aleReimondo@smalltalking.net
Edgar
2008/11/26 Bert Freudenberg bert@freudenbergs.de:
On 26.11.2008, at 09:48, Igor Stasenko wrote:
2008/11/26 Trygve Reenskaug trygver@ifi.uio.no:
On 26.11.2008 05:32, Igor Stasenko wrote:
- Everything is an object
- Objects communicate by sending and receiving messages (in terms of
objects) 3. Objects has their own memory (in terms of objects)
- Every object is an instance of class (which must be an object)
- The class holds the shared behavior for its instances (in the form
of objects in a program list) 6. To eval a program list, control is passed to the first object and the remainder is treated as its message
so, where in these statements you find anything about inheritance, or something where it says that subclass(es) should have any assumptions about the ways how superclass is storing its instances in memory, and therefore a subclass allowed to directly manipulate the object's state without consulting with superclass?
I'm afraid Alan wasn't as precise as he should have been here.
I think he did this intentionally, because a precise parts is up to implementation. The principles above is most generic ones. Btw, notice a line between 3 and 4, its not just a random stroke - its actually shows a first step from most generic to more specific.
Just a meta remark - I find it highly amusing how people dissect the Gospel of Alan, even interpreting it literally. He must get quite a chuckle from that ;)
:) i didn't meant to dissect it. Just wanted to point out, that we in the same boat (smalltalk) as long as design follows these basic principles. The rest is implementation details.
- Bert -
On 25-Nov-2008, at 11:32 PM, Igor Stasenko wrote:
2008/11/26 Greg A. Woods; Planix, Inc. woods@planix.ca:
On 25-Nov-2008, at 10:45 PM, Igor Stasenko wrote:
My understanding of inheritance is different, in short: A subclass of particular class is a _specialization_ of base class, not _expansion_.
Well when you're defining the behaviour of objects in an OO system there's not really any difference between "specialization" and "expansion" -- the subclass is _adding_ changes to the definitions given in the superclass. Perhaps the changes will over-ride a behaviour in the superclass, or modify it in some way, but fundamentally a subclass is always adding something to the superclass in order to create the new subclass it defines.
No, specialization and expansion having really different meanings, if you consider a class, like SmallInteger. Following your understanding, one may want to expand a SmallInteger class by subclassing it and providing additional behavior. Following my understanding, SmallInteger class is highly specialized class, up to the point that its impossible to specialize it further.
What you say is true, but irrelevant to my point.
If you want to create a more specialized subclass of SmallInteger you must _add_ code by defining that new subclass. A subclass always, by definition, adds new additional code to the class it inherits from.
Here I'm looking at the actual process of defining a subclass. Literally and figuratively. In Smalltalk-80 a subclass always adds code to the class it inherits from, regardless of whether the intent is to create a specialized form of the superclass or to create an expanded form of the superclass.
Sorry, I probably should have been more explicit in the first place about the perspective I'm seeing this issue from.
Of course i know it. Just a small(talk) correction: classes are objects as well and having state as well.
Sure, but that's just a feature of the implementation that comes out of the goal to have _everything_ be an object. That's just the way the system describes itself to itself to keep the VM small and simple and primitive and perhaps also in some minor way to try to express the system within itself in the same way lisp does. It does help show that the design is complete and elegant too of course, and in many ways it perhaps makes the implementation easier to design, work with, and even use.
From "The Early History of Smalltalk" by Alan Kay
- Everything is an object
- Objects communicate by sending and receiving messages (in terms
of objects) 3. Objects has their own memory (in terms of objects)
- Every object is an instance of class (which must be an object)
- The class holds the shared behavior for its instances (in the form
of objects in a program list) 6. To eval a program list, control is passed to the first object and the remainder is treated as its message
so, where in these statements you find anything about inheritance, or something where it says that subclass(es) should have any assumptions about the ways how superclass is storing its instances in memory, and therefore a subclass allowed to directly manipulate the object's state without consulting with superclass?
Indeed you don't find anything about inheritance there of course. It's not relevant in that context.
Inheritance is an additional feature of Classes, one which adds to an OO system. There were, IIRC, earlier Smalltalks which didn't have inheritance, but Smalltalk-80 does, in the form of subclassing. To quote directly from the blue book (p. 56):
"Lack of intersection in class membership is a limitation on design in an object-oriented system since it does not allow any sharing between class descriptions. [[....]] If class memberships are not allowed to overlap, this type of partial similarity between two object cannot be guaranteed by the system."
I.e. you could sort of create a subclass by simply copying the whole class definition you wish to inherit from, then modify it to your liking (this has been done an infinite number of times in uses of non- OO languages!). However then you lose the support of the system to maintain the relationship between the shared parts of the superclass definition(s) and the subclasses that inherit from it (or indeed even just between the superclass and its sole subclass in the case where the superclass is not actually an abstract class).
The price you pay of course for the assistance of the system in this way is that maintainers of the superclass(es) must now take into account the needs of subclass(es), both existing and potential future ones too; eg. instance variables (and everything else) defined in the superclass are also actually part of the subclass. TANSTAAFL
Subclassing is just a way of appearing to dynamically copy code and then allowing for controlled ways to modify it and add to it. Again the free lunch is taken away by the need for the current implementation to recompile subclasses and potentially also fiddle with all object instances of those subclasses when certain attributes (such as instance variables) are changed in the superclass definition.
This essay is interesting in this context, and perhaps even slightly relevant to the whole thread:
"The Dreaded Super" by Kent Beck first published June 1992 in Smalltalk Report http://books.google.ca/books?id=Y7FwNB4GV4EC&pg=PA81
On Wed, Nov 26, 2008 at 10:22 AM, Greg A. Woods; Planix, Inc. < woods@planix.ca> wrote:
On 25-Nov-2008, at 11:32 PM, Igor Stasenko wrote:
2008/11/26 Greg A. Woods; Planix, Inc. woods@planix.ca:
On 25-Nov-2008, at 10:45 PM, Igor Stasenko wrote:
My understanding of inheritance is different, in short: A subclass of particular class is a _specialization_ of base class, not _expansion_.
Well when you're defining the behaviour of objects in an OO system there's not really any difference between "specialization" and "expansion" -- the subclass is _adding_ changes to the definitions given in the superclass. Perhaps the changes will over-ride a behaviour in the superclass, or modify it in some way, but fundamentally a subclass is always adding something to the superclass in order to create the new subclass it defines.
No, specialization and expansion having really different meanings, if you consider a class, like SmallInteger. Following your understanding, one may want to expand a SmallInteger class by subclassing it and providing additional behavior. Following my understanding, SmallInteger class is highly specialized class, up to the point that its impossible to specialize it further.
What you say is true, but irrelevant to my point.
If you want to create a more specialized subclass of SmallInteger you must _add_ code by defining that new subclass. A subclass always, by definition, adds new additional code to the class it inherits from.
Then choose a different class than SmallInteger to make your point. SmallInteger is rather special, an immediate class whose instances are represented specially by encoding their value in an object pointer, so that a reference to a SmallInteger *is* the SmallInteger. In Squeak SmallInteger is the only such class. Subclasses of SmallInteger by necessity are normal objects so that when any of the inherited behaviour is used nonsense results because the subclass instance's normal pointer is interpreted as a SmallInteger.
Make your point with any other class. Using SmallInteger will simply create cognitive dissonance and defocus the conversation.
Here I'm looking at the actual process of defining a subclass. Literally and figuratively. In Smalltalk-80 a subclass always adds code to the class it inherits from, regardless of whether the intent is to create a specialized form of the superclass or to create an expanded form of the superclass.
Sorry, I probably should have been more explicit in the first place about the perspective I'm seeing this issue from.
Of course i know it. Just a small(talk) correction: classes are
objects as well and having state as well.
Sure, but that's just a feature of the implementation that comes out of the goal to have _everything_ be an object. That's just the way the system describes itself to itself to keep the VM small and simple and primitive and perhaps also in some minor way to try to express the system within itself in the same way lisp does. It does help show that the design is complete and elegant too of course, and in many ways it perhaps makes the implementation easier to design, work with, and even use.
From "The Early History of Smalltalk" by Alan Kay
- Everything is an object
- Objects communicate by sending and receiving messages (in terms of
objects) 3. Objects has their own memory (in terms of objects)
- Every object is an instance of class (which must be an object)
- The class holds the shared behavior for its instances (in the form
of objects in a program list) 6. To eval a program list, control is passed to the first object and the remainder is treated as its message
so, where in these statements you find anything about inheritance, or something where it says that subclass(es) should have any assumptions about the ways how superclass is storing its instances in memory, and therefore a subclass allowed to directly manipulate the object's state without consulting with superclass?
Indeed you don't find anything about inheritance there of course. It's not relevant in that context.
Inheritance is an additional feature of Classes, one which adds to an OO system. There were, IIRC, earlier Smalltalks which didn't have inheritance, but Smalltalk-80 does, in the form of subclassing. To quote directly from the blue book (p. 56):
"Lack of intersection in class membership is a limitation on design
in an object-oriented system since it does not allow any sharing between class descriptions. [[....]] If class memberships are not allowed to overlap, this type of partial similarity between two object cannot be guaranteed by the system."
I.e. you could sort of create a subclass by simply copying the whole class definition you wish to inherit from, then modify it to your liking (this has been done an infinite number of times in uses of non-OO languages!). However then you lose the support of the system to maintain the relationship between the shared parts of the superclass definition(s) and the subclasses that inherit from it (or indeed even just between the superclass and its sole subclass in the case where the superclass is not actually an abstract class).
The price you pay of course for the assistance of the system in this way is that maintainers of the superclass(es) must now take into account the needs of subclass(es), both existing and potential future ones too; eg. instance variables (and everything else) defined in the superclass are also actually part of the subclass. TANSTAAFL
Subclassing is just a way of appearing to dynamically copy code and then allowing for controlled ways to modify it and add to it. Again the free lunch is taken away by the need for the current implementation to recompile subclasses and potentially also fiddle with all object instances of those subclasses when certain attributes (such as instance variables) are changed in the superclass definition.
This essay is interesting in this context, and perhaps even slightly relevant to the whole thread:
"The Dreaded Super" by Kent Beck first published June 1992 in Smalltalk Report http://books.google.ca/books?id=Y7FwNB4GV4EC&pg=PA81
-- Greg A. Woods; Planix, Inc. woods@planix.ca
On 26-Nov-2008, at 1:32 PM, Eliot Miranda wrote:
Then choose a different class than SmallInteger to make your point.
Sorry, it wasn't my choice in the first place.
I'm not sure it's relevant to my point either, but I'm too ignorant about the details to know for sure so I'll take your word for it.
I think any normal class would do, though perhaps any user-defined class would be best -- the point is simply that subclasses are defined by adding stuff to the definition of an existing class hierarchy. Whether the additions change the behaviour of existing methods or not, add new instance variables, or not, or add new methods or not, doesn't really take away from the fact that the subclass is defined by adding new definitions to its superclass.
Any class (except I think Object itself of course) is really just the combined definition of all the superclasses in its hierarchy. If it weren't for "super" (and some other meta-level stuff I think we can safely gloss over) there would be no real way for an object to distinguish which parts of itself are from which levels in the class hierarchy that it is entirely derived from. At least that's how I've come to understand classes and inheritance in Smalltalk-80.
Greg A. Woods; Planix, Inc. wrote:
I.e. you could sort of create a subclass by simply copying the whole class definition you wish to inherit from, then modify it to your liking (this has been done an infinite number of times in uses of non-OO languages!). However then you lose the support of the system to maintain the relationship between the shared parts of the superclass definition(s) and the subclasses that inherit from it (or indeed even just between the superclass and its sole subclass in the case where the superclass is not actually an abstract class).
Traits?
On 26-Nov-2008, at 1:54 PM, Tony Garnock-Jones wrote:
Greg A. Woods; Planix, Inc. wrote:
I.e. you could sort of create a subclass by simply copying the whole class definition you wish to inherit from, then modify it to your liking (this has been done an infinite number of times in uses of non-OO languages!). However then you lose the support of the system to maintain the relationship between the shared parts of the superclass definition(s) and the subclasses that inherit from it (or indeed even just between the superclass and its sole subclass in the case where the superclass is not actually an abstract class).
Traits?
Maybe. I don't know.
I definitely don't know how Traits would/could work in Smalltalk and what benefit they would bring.
Does anyone have a reference to a good outline of what Traits do for Smalltalk? Do they provide the ability to hide instance variables from subclasses -- or eliminate the need for recompiling subclasses? Do they simply add a new feature, or do they replace something in (or even all of) classes or metaclasses?
www.iam.unibe.ch/~scg/Research/Traits
See also prior discussions on traits on this list:
http://www.google.com/search?&q=site%3Ahttp%3A%2F%2Flists.squeakfoundati...
On Wed, Nov 26, 2008 at 2:32 PM, Greg A. Woods; Planix, Inc. woods@planix.ca wrote:
On 26-Nov-2008, at 1:54 PM, Tony Garnock-Jones wrote:
Greg A. Woods; Planix, Inc. wrote:
I.e. you could sort of create a subclass by simply copying the whole class definition you wish to inherit from, then modify it to your liking (this has been done an infinite number of times in uses of non-OO languages!). However then you lose the support of the system to maintain the relationship between the shared parts of the superclass definition(s) and the subclasses that inherit from it (or indeed even just between the superclass and its sole subclass in the case where the superclass is not actually an abstract class).
Traits?
Maybe. I don't know.
I definitely don't know how Traits would/could work in Smalltalk and what benefit they would bring.
Does anyone have a reference to a good outline of what Traits do for Smalltalk? Do they provide the ability to hide instance variables from subclasses -- or eliminate the need for recompiling subclasses? Do they simply add a new feature, or do they replace something in (or even all of) classes or metaclasses?
-- Greg A. Woods; Planix, Inc. woods@planix.ca
On Nov 25, 2008, at 7:45 PM, Igor Stasenko wrote:
My understanding of inheritance is different, in short: A subclass of particular class is a _specialization_ of base class, not _expansion_.
In this context, I sometimes wonder if Square should inherit from Rectangle (a specialization in which width and height are equal), or Rectangle should inherit from Square (adding an instance variable). Am I right that you would have Square inherits from Rectangle (Square being more specialized)? But then it feels like we are wasting an instance variable (since Rectangle would have two).
James
2008/11/26 James Foster Smalltalk@jgfoster.net:
On Nov 25, 2008, at 7:45 PM, Igor Stasenko wrote:
My understanding of inheritance is different, in short: A subclass of particular class is a _specialization_ of base class, not _expansion_.
In this context, I sometimes wonder if Square should inherit from Rectangle (a specialization in which width and height are equal), or Rectangle should inherit from Square (adding an instance variable). Am I right that you would have Square inherits from Rectangle (Square being more specialized)? But then it feels like we are wasting an instance variable (since Rectangle would have two).
Good example. Right , Square looks more specialized. And since it always having width == height , it looks like an error to keep a redundant state. So, i don't see much problem. We can define a common ancestor, like TwoDimensionalObject, having #width, #height abstract accessors. And then, define two subclasses Square and Rectangle which have different specialization of TwoDimensionalObject because require a different number of slots for storing data.
There are many examples of such approach. Consider a Number - Float - BigInteger classes. Float and BigInteger sharing common behavior which comes from Number but storage format is completely different. Same is for String - ByteString and WideString. This actually shows that inheritance is not relevant with objects format.
James
James Foster a écrit :
On Nov 25, 2008, at 7:45 PM, Igor Stasenko wrote:
My understanding of inheritance is different, in short: A subclass of particular class is a _specialization_ of base class, not _expansion_.
In this context, I sometimes wonder if Square should inherit from Rectangle (a specialization in which width and height are equal), or Rectangle should inherit from Square (adding an instance variable). Am I right that you would have Square inherits from Rectangle (Square being more specialized)? But then it feels like we are wasting an instance variable (since Rectangle would have two).
James
Beware, you're dangerously sliping to multiple inheritance because your Square might also be a lozenge :)
Nicolas
nicolas cellier wrote:
James Foster a écrit :
On Nov 25, 2008, at 7:45 PM, Igor Stasenko wrote:
My understanding of inheritance is different, in short: A subclass of particular class is a _specialization_ of base class, not _expansion_.
In this context, I sometimes wonder if Square should inherit from Rectangle (a specialization in which width and height are equal), or Rectangle should inherit from Square (adding an instance variable). Am I right that you would have Square inherits from Rectangle (Square being more specialized)? But then it feels like we are wasting an instance variable (since Rectangle would have two).
Beware, you're dangerously sliping to multiple inheritance because your Square might also be a lozenge :)
With the Rectangle as subclass of Square option this wouldn't be a problem - you would just have two different subclasses of Square.
Could Rectangle be a subclass of Square? Sure:
- Square instance variables: center, size, orientation
- Rectangle adds this instance variable: aspectRatio
We can make Ellipse a subclass of Circle using the same style. We can even have an #aspectRatio method in Square and Circle which always returns 1 and then we can move some of the more general code up in the classes hierarchy if we want to.
For raster graphics it is convenient to define Rectangles as always parallel to the screen axis so that just two points are enough to fully identify them. Perhaps calling them RasterRects instead would have made us think more clearly about them. We later moved to vector graphics (Balloon) but were stuck with the historic baggage.
-- Jecel P.S.: I am aware that even in this scheme you might want Parallelogram to inherit from both Rectangle and Lozenge (actually, Rhombus is more generic) and then you have the multiple inheritance problem again. Which is what Traits are for...
On Tue, Nov 25, 2008 at 7:19 PM, Greg A. Woods; Planix, Inc. woods@planix.ca wrote:
An object shouldn't have to use accessor methods to get at its own internal state, no matter where in the class hierarchy its state may be defined. "super" is only needed to get around explicit re-definitions done by the subclass.
And thus the fragile superclass problem is born.
The thing is, there are two overlapping but different perspectives here. From an object-centric view, sure, any state or behavior is there in the object and where in the hierarchy it comes from is a minor detail.
However, as far as the code goes, we are talking about distinct chunks of code, potentially written, maintained and updated by different people. A subclass depends on the superclass in the same way that code using a library is a dependent of that library's API. Managing that dependency has maintainability repercussions, and weakening it is a good thing.
Cheers,
--Vassili
On 25-Nov-2008, at 10:58 PM, Vassili Bykov wrote:
And thus the fragile superclass problem is born.
:-)
The thing is, there are two overlapping but different perspectives here. From an object-centric view, sure, any state or behavior is there in the object and where in the hierarchy it comes from is a minor detail.
However, as far as the code goes, we are talking about distinct chunks of code, potentially written, maintained and updated by different people. A subclass depends on the superclass in the same way that code using a library is a dependent of that library's API. Managing that dependency has maintainability repercussions, and weakening it is a good thing.
If my memory isn't failing me too much I seem to remember going to a talk about a dozen years ago by Adele Goldberg where she talked about the need to form contracts between producers and consumers of class definitions.
And thus the fragile superclass problem is born.
The thing is, there are two overlapping but different perspectives here. From an object-centric view, sure, any state or behavior is there in the object and where in the hierarchy it comes from is a minor detail.
However, as far as the code goes, we are talking about distinct chunks of code, potentially written, maintained and updated by different people. A subclass depends on the superclass in the same way that code using a library is a dependent of that library's API. Managing that dependency has maintainability repercussions, and weakening it is a good thing.
Cheers,
--Vassili
Not at the expense of encapsulation by forcing access to instance variables to go through public accessors. Protected accessors (visible only to self and subclasses) might be a compromise but then you open up the whole can of worms going down that path where the language starts trying to protect the programmer from himself with all kinds of visibility options for methods and classes.
This leads to things like csharp and java's final/sealed classes where the author of a class decides all future uses of the class. I prefer a language to enable me, not restrict me. I don't want the author of a class deciding for me how I might decide to use that class in the future. If the fragile base class problem is the price, then I'm happy to pay it.
Ramon Leon http://onsmalltalk.com
On 26-Nov-2008, at 2:41 PM, Ramon Leon wrote:
Not at the expense of encapsulation by forcing access to instance variables to go through public accessors. Protected accessors (visible only to self and subclasses) might be a compromise but then you open up the whole can of worms going down that path where the language starts trying to protect the programmer from himself with all kinds of visibility options for methods and classes.
This leads to things like csharp and java's final/sealed classes where the author of a class decides all future uses of the class. I prefer a language to enable me, not restrict me. I don't want the author of a class deciding for me how I might decide to use that class in the future. If the fragile base class problem is the price, then I'm happy to pay it.
Exactly. :-)
This is even hinted at broadly in the blue book -- i.e. its not a new problem by any stretch of the imagination.
In fact I think this is where things outside the language and its implementation are more suitable to help with such problems. Eg. tools in the development environment, perhaps using structured documentation built into class definitions, might offer the necessary bridge. Perhaps something like a (pardon my association) lint-like tool for seeking out and managing inter-class dependencies and constraints (because this issue extends beyond just subclasses and superclasses and cuts across all classes which interact in any way).
On Wed, Nov 26, 2008 at 11:41 AM, Ramon Leon ramon.leon@allresnet.com wrote:
However, as far as the code goes, we are talking about distinct chunks of code, potentially written, maintained and updated by different people. A subclass depends on the superclass in the same way that code using a library is a dependent of that library's API. Managing that dependency has maintainability repercussions, and weakening it is a good thing.
Not at the expense of encapsulation by forcing access to instance variables to go through public accessors. Protected accessors (visible only to self and subclasses) might be a compromise but then you open up the whole can of worms going down that path where the language starts trying to protect the programmer from himself with all kinds of visibility options for methods and classes.
This leads to things like csharp and java's final/sealed classes where the author of a class decides all future uses of the class. I prefer a language to enable me, not restrict me. I don't want the author of a class deciding for me how I might decide to use that class in the future. If the fragile base class problem is the price, then I'm happy to pay it.
So you are lamenting loss of encapsulation (a restrictive feature) in the first paragraph, and decrying loss of freedom to restrictive features in the second. Come on, pick one. If you don't want the author of a class deciding how you might decide to use it, how can you put up with him deciding what instance variables are off-limits and have no public accessors?
Indeed what I had in mind were Newspeak-style access modifiers combined with message-based slot access. Their combination in fact improves encapsulation. And no, they don't lead to final classes.
Cheers,
--Vassili
Btw, regarding instance variables:
i just stepped on error, when tried to add an instance variable in superclass while variable with that name already exists in a subclass. Note, that adding non-conflicting variable name to an existing class can't be an error. But because we need to recompile subclasses, we should scan all subclasses to detect potential naming duplication.
From user's perspective it looks like he unable to alter a base class
without consulting with subclasses. And this is awfully wrong , of course :)
So you are lamenting loss of encapsulation (a restrictive feature) in the first paragraph, and decrying loss of freedom to restrictive features in the second. Come on, pick one.
Because I consider encapsulation something that exists between objects, not between super and subclass. I don't consider that a conflict, interesting that you do.
If you don't want the author of a class deciding how you might decide to use it, how can you put up with him deciding what instance variables are off-limits and have no public accessors?
Again, the object class divide; he can't, in Smalltalk, restrict me from seeing instance variables if I subclass his class. I like it this way. When I'm building a new class it's up to me whether to choose to use inheritance or not and if I choose to do so it's because I want to share code or extend or specialize that class and I want direct access to anything in that superclass. My class is not his class and if I do something that makes my classes instances misbehave that's my problem, not his.
The public interface of instances of his objects however, is his problem and he has every right to encapsulate and protect the implementation of his instances. There simply is a difference, to me at least, between using someone else's objects, and using someone else's classes as a template to build my own objects. I accept encapsulation as beneficial and necessary in the former case but as harmful and restrictive in the latter.
I base this judgment on the vocabulary I find myself muttering in each case, usually profanity in the latter case while I hunt down source code to change the original authors access modifiers.
Indeed what I had in mind were Newspeak-style access modifiers combined with message-based slot access. Their combination in fact improves encapsulation. And no, they don't lead to final classes.
Cheers,
--Vassili
They certainly start down that road, final and sealed are just as much access modifiers as public, private, or protected; however, if not applied zealously and taken too far (i.e. final classes), I agree it's not a bad solution. I would prefer not to have two ways to access instances vars so if protected accessors were the solution I'd want them to replace all direct instance variable access, even within a single class so slots make perfect sense. But at this point, we're not really talking about Smalltalk any more.
I won't pretend to be a language designer or say I know what the perfect balance of features is, but I rather like the balance Smalltalk struck with no access modifiers, public methods, protected instances variables, and trust in the programmer.
Ramon Leon http://onsmalltalk.com
2008/11/27 Ramon Leon ramon.leon@allresnet.com:
So you are lamenting loss of encapsulation (a restrictive feature) in the first paragraph, and decrying loss of freedom to restrictive features in the second. Come on, pick one.
Because I consider encapsulation something that exists between objects, not between super and subclass. I don't consider that a conflict, interesting that you do.
If you don't want the author of a class deciding how you might decide to use it, how can you put up with him deciding what instance variables are off-limits and have no public accessors?
Again, the object class divide; he can't, in Smalltalk, restrict me from seeing instance variables if I subclass his class. I like it this way. When I'm building a new class it's up to me whether to choose to use inheritance or not and if I choose to do so it's because I want to share code or extend or specialize that class and I want direct access to anything in that superclass. My class is not his class and if I do something that makes my classes instances misbehave that's my problem, not his.
The public interface of instances of his objects however, is his problem and he has every right to encapsulate and protect the implementation of his instances. There simply is a difference, to me at least, between using someone else's objects, and using someone else's classes as a template to build my own objects. I accept encapsulation as beneficial and necessary in the former case but as harmful and restrictive in the latter.
I base this judgment on the vocabulary I find myself muttering in each case, usually profanity in the latter case while I hunt down source code to change the original authors access modifiers.
Indeed what I had in mind were Newspeak-style access modifiers combined with message-based slot access. Their combination in fact improves encapsulation. And no, they don't lead to final classes.
Cheers,
--Vassili
They certainly start down that road, final and sealed are just as much access modifiers as public, private, or protected; however, if not applied zealously and taken too far (i.e. final classes), I agree it's not a bad solution. I would prefer not to have two ways to access instances vars so if protected accessors were the solution I'd want them to replace all direct instance variable access, even within a single class so slots make perfect sense. But at this point, we're not really talking about Smalltalk any more.
I won't pretend to be a language designer or say I know what the perfect balance of features is, but I rather like the balance Smalltalk struck with no access modifiers, public methods, protected instances variables, and trust in the programmer.
Concerning security models and principles it is based upon, i very like a simple & powerful security model used in E (Erights).
From http://www.erights.org/elib/capability/ode/overview.html
---- Capability Security. The Granovetter Operator becomes a security primitive given the following constraint: If Bob does not already have a reference to Carol, Bob can only come to have a reference to Carol if a third party, such as Alice,
* already has a reference to Carol, and * already has a reference to Bob, and * voluntarily decides to share with Bob her reference to Carol.
Adding this property to an object system transforms it into a capability system. In a capability system, only connectivity begets connectivity. In a capability system, an object's authority to affect the world outside itself is determined solely by what references it holds, since the only way the object can cause an external effect is to send a message via one of these references. Consequently, the mechanics of reference-passing determine how authority can change over time. ----
Its easy to show, that access modifiers or class sealing is not the answer to security. Simply do not give away an object references to untrusted code which would allow it to operate directly with critical system resources.
In short, a principle is very simple: you can't break things which you cannot reach or see.
Ramon Leon http://onsmalltalk.com
On Wed, Nov 26, 2008 at 9:52 PM, Igor Stasenko siguctua@gmail.com wrote:
Its easy to show, that access modifiers or class sealing is not the answer to security. Simply do not give away an object references to untrusted code which would allow it to operate directly with critical system resources.
In short, a principle is very simple: you can't break things which you cannot reach or see.
Yes, and also as I just wrote in another post, it's a mistake to even expect that access modifiers are there to provide security (despite some unfortunate examples in mainstream literature). They are artifacts that work at completely different architectural levels. Access modifiers are there to ensure certain invariants about the code. Thus they are a code-level trust structuring mechanism, not object-level trust structuring that capabilities build.
Cheers,
--Vassili
On Wed, Nov 26, 2008 at 8:42 PM, Ramon Leon ramon.leon@allresnet.com wrote:
So you are lamenting loss of encapsulation (a restrictive feature) in the first paragraph, and decrying loss of freedom to restrictive features in the second. Come on, pick one.
Because I consider encapsulation something that exists between objects, not between super and subclass. I don't consider that a conflict, interesting that you do.
Then you don't seem to realize that we work with classes and their code, not objects. It's code dependencies that translate into maintenance. As for objects, their composition from class blueprints is not necessarily as unambiguous as you are used to. In Newspeak, for example, you can't always point and say, "this will be the superclass of this guy" because the superclass is late-bound. You can't even compile that sort of thing easily unless you take messages further, to communicate within objects as well as between them. I view that information hiding as beneficial enough to even overlook the sacrifice encapsulation in its naive understanding (see below what I really think about access modifiers).
Encapsulation is an interesting thing in that popular literature promotes a very narrow view of it. It often starts with a reasonable explanation of information hiding as a noble architectural principle, then degrades into "so in a nutshell, store your data in private fields". That confuses information hiding with security. Information hiding helps structure code, security when it's inappropriate only gets in the way. There are languages where all object slots are accessible--CLOS, for example. I'd like to hear a C++ programmer declare CLOS a non-OO language because it lacks "encapsulation".
This narrow view is the evidence of how little the mainstream gets OO. The mechanism for encapsulation in its true sense is so ingrained in Smalltalk you can't take it out--it's messages, with the late binding of a name to its interpretation. There is no other way to communicate with an object. Too bad for C++, but that is what OO is about, not "encapsulation, inheritance, polymorphism". Message-based computation enables information hiding and promotes weaker code dependencies.
And now I can admit that I view access modifiers for slot accessor messages as more of a political tool to shut up those who would cry "aha, no encapsulation!" as soon as they saw messages used for slot access. I don't think they are an important safeguard preventing horrors from happening.
Here is what I find interesting about the belief that encapsulation is critically flawed without object data hidden away. There is enough Smalltalk code out there written in variable-exposing style. Large complex systems have been built in CLOS with its wide open object slots. Where are the real horror stories about this practice? I mean real horror--not "I remember there was this bug once..." but rather "...and man, we had to spend weeks fixing that crap before it started working".
All you hear are speculations how exposed variables are bad because encapsulation is good. That sounds to me like "dynamic typing is dangerous because you get runtime errors, and static typing would catch at least some of those". An intellectual bogeyman. It may sound reasonable as an isolated statement, but anyone with some practical experience will know better. Having open slots at your disposal is one thing, using that access indiscriminately to hurt yourself is a completely different one.
One last point, the most likely reason instance variables are the way they are is because it was a necessary performance compromise for the '70s hardware. No reason to consider that as some sort of heavenly harmony, even if you are used to it.
Cheers,
--Vassili
On Wed, Nov 26, 2008 at 8:42 PM, Ramon Leon ramon.leon@allresnet.com wrote:
So you are lamenting loss of encapsulation (a restrictive
feature) in
the first paragraph, and decrying loss of freedom to restrictive features in the second. Come on, pick one.
Because I consider encapsulation something that exists
between objects, not
between super and subclass. I don't consider that a
conflict, interesting
that you do.
Then you don't seem to realize that we work with classes and their code, not objects. It's code dependencies that translate into maintenance. As for objects, their composition from class blueprints is not necessarily as unambiguous as you are used to. In Newspeak, for example, you can't always point and say, "this will be the superclass of this guy" because the superclass is late-bound. You can't even compile that sort of thing easily unless you take messages further, to communicate within objects as well as between them. I view that information hiding as beneficial enough to even overlook the sacrifice encapsulation in its naive understanding (see below what I really think about access modifiers).
Encapsulation is an interesting thing in that popular literature promotes a very narrow view of it. It often starts with a reasonable explanation of information hiding as a noble architectural principle, then degrades into "so in a nutshell, store your data in private fields". That confuses information hiding with security. Information hiding helps structure code, security when it's inappropriate only gets in the way. There are languages where all object slots are accessible--CLOS, for example. I'd like to hear a C++ programmer declare CLOS a non-OO language because it lacks "encapsulation".
This narrow view is the evidence of how little the mainstream gets OO. The mechanism for encapsulation in its true sense is so ingrained in Smalltalk you can't take it out--it's messages, with the late binding of a name to its interpretation. There is no other way to communicate with an object. Too bad for C++, but that is what OO is about, not "encapsulation, inheritance, polymorphism". Message-based computation enables information hiding and promotes weaker code dependencies.
And now I can admit that I view access modifiers for slot accessor messages as more of a political tool to shut up those who would cry "aha, no encapsulation!" as soon as they saw messages used for slot access. I don't think they are an important safeguard preventing horrors from happening.
Here is what I find interesting about the belief that encapsulation is critically flawed without object data hidden away. There is enough Smalltalk code out there written in variable-exposing style. Large complex systems have been built in CLOS with its wide open object slots. Where are the real horror stories about this practice? I mean real horror--not "I remember there was this bug once..." but rather "...and man, we had to spend weeks fixing that crap before it started working".
All you hear are speculations how exposed variables are bad because encapsulation is good. That sounds to me like "dynamic typing is dangerous because you get runtime errors, and static typing would catch at least some of those". An intellectual bogeyman. It may sound reasonable as an isolated statement, but anyone with some practical experience will know better. Having open slots at your disposal is one thing, using that access indiscriminately to hurt yourself is a completely different one.
One last point, the most likely reason instance variables are the way they are is because it was a necessary performance compromise for the '70s hardware. No reason to consider that as some sort of heavenly harmony, even if you are used to it.
Cheers,
--Vassili
Definitely some food for thought.
Ramon Leon http://onsmalltalk.com
On 26.11.2008 01:57, Igor Stasenko wrote:
I like the idea of hiding the state/storage specific details from eyes of subclasses. It makes irrelevant, in what format or where particular object holds its state. As long as you providing messages to access it, it could be anything.
This "hiding" comes at a cost. Object state can only be accessed from within the object itself. Accessor methods are public, they can be accessed from anywhere. --Trygve
Hi all.
What would people's reaction be if a class was prevented from being able to directly access its superclass's instance variables?
I would object.
A subclass should use accessor methods to access a superclass's instance variables.
Says who?
Is there any particular reason subclasses get access to superclass instance variables? I think it breaks encapsulation.
Then we have different definitions of encapsulation. To me encapsulation means one object can not directly access the state of another object but must use messages for communication.
If class #B inherits from class #A an instance of class #B is only *one object*; i.e. super is not another object but the same object as self and thus the object should have direct access to *all* of its own instance variables regardless of where they lie in the inheritance tree. I don't think encapsulation was intended to protect an object from itself. That's my 2 cents!
Ramon Leon http://onsmalltalk.com
Hi all.
On Wed, Nov 26, 2008 at 12:49 PM, Ramon Leon ramon.leon@allresnet.comwrote:
Hi all.
What would people's reaction be if a class was prevented from being able to directly access its superclass's instance variables?
I would object.
I'm interested in why you'd object. Do you have a deeper reason than "it makes coding harder"?
Is there any particular reason subclasses get access to superclass instance variables? I think it breaks encapsulation.
Then we have different definitions of encapsulation. To me encapsulation means one object can not directly access the state of another object but must use messages for communication.
If class #B inherits from class #A an instance of class #B is only *one object*; i.e. super is not another object but the same object as self and thus the object should have direct access to *all* of its own instance variables regardless of where they lie in the inheritance tree. I don't think encapsulation was intended to protect an object from itself. That's my 2 cents!
I'm referring to encapsulation of an implementation of something. If a superclass is an "implementation of something", a subclass is a user and extender of that "implementation of something". Allowing a subclass direct access to the innards of its superclass prevents that superclass from being able to protect its carefully guarded state from meddling by subclasses.
This is relevant in the area of secure programming for my SecureSqueak project, although I can't think of a good example yet where it would really be a problem.
Say you have a class with a carefully guarded secret in it. It would then be possible for untrusted, remotely loaded code to be a subclass of that class and then give out that secret. This makes several assumptions though: firstly that you can somehow create an instance of your subclass with that secret state (which is unlikely) and secondly that the remotely loaded code actually has access to the class and is able to become a subclass of it.
Gulik.
On 25-Nov-2008, at 9:20 PM, Michael van der Gulik wrote:
I'm referring to encapsulation of an implementation of something. If a superclass is an "implementation of something", a subclass is a user and extender of that "implementation of something".
Well, umm, no, I don't think so -- a subclass is, by definition, an _extension_ of the class it inherits from.
Allowing a subclass direct access to the innards of its superclass prevents that superclass from being able to protect its carefully guarded state from meddling by subclasses.
If such protection seems necessary then I'd say there's something extremely broken in the overall design of that part of the class hierarchy in question.
This is relevant in the area of secure programming for my SecureSqueak project, although I can't think of a good example yet where it would really be a problem.
Perhaps you could start by explaining some of the theory about how any kind of "secure" (do you really just mean "safe"?) programming techniques can be aided by what you seem to be describing here.
Say you have a class with a carefully guarded secret in it. It would then be possible for untrusted, remotely loaded code to be a subclass of that class and then give out that secret.
Ah, perhaps you don't mean secure programming, but rather actual data security.
I really don't understand your security model here. It doesn't seem to be related to or compatible with the object oriented programming model of Smalltalk at all, at least as I understand things. A subclass is an extension of its superclass. An object which is an instance of the subclass inherits all the qualities of the superclass(es) too.
An object that is only derived from the "superclass" is a separate object. And it isn't an instance sharing any quality of any subclass that may inherit from its class, let alone sharing any data with any instance of any subclass.
This makes several assumptions though: firstly that you can somehow create an instance of your subclass with that secret state (which is unlikely) and secondly that the remotely loaded code actually has access to the class and is able to become a subclass of it.
Indeed, that part is just plain nonsensical.
You seem to be confusing the definition of objects with the actual objects themselves.
If you're really trying to create a model where objects created as instances of classes which have been remotely loaded, then you need to create some sort of partitioned VM storage model such that the VM will only pass messages between objects within a given partition, and perhaps one way from a parent partition. I don't think this can really work very well in a Smalltalk system though, but perhaps I'm missing something. If I load untrusted code I basically have to do it in a different VM image which has been carefully constructed so as to contain only public data and which has built-in controls which will only allow it to access those parts of the outside system environment which I would feel safe allowing untrusted code to access. Perhaps this VM image could be dynamically created and managed by another full "parent" VM. If I'm not mistaken this is kind of sort of how the Java VM security model is supposed to work.
squeak-dev@lists.squeakfoundation.org