Hi Stéphane,
Yes, I ***really*** do think that the Collection hierarchy is a "toy" example. Allow me to explain why:
What was done with the Collection hierarchy was essentially a refactoring to use Traits. It wasn't a new design from requirements. And while the Collection hierachy is a fabulous and powerful invention, it is really just a bunch of generic components to be used in building more complex systems.
My point was that I don't think that the capabilities Traits offers matches up with the way that commercial software is created in the "real" world.
I work on a product that is built from over ten thousand source files and has hundreds of developers working on it. The system runs on at least 8 different target CPU's (obviously, not all of the code runs on all eight different CPU types), and includes code written in C, C++, Java, JavaScript, Pascal, various assembly languages, and includes over 300 megabytes of executable code. I am not commenting on the quality of code, only the quantity here. The quality level of the code by any objective standards varies widely, depending on the skill and experience of the people who worked on it and the other constraints placed on the development (i.e. if we can't demonstrate the new feature to an important customer by the end of the (pick some time interval - quarter, month, week, etc.) we will lose a sale worth millions to an evil competitor).
I think what I am describing here is how a lot of software gets created in the real world, and in this kind of environment the code never gets past the "make it work" stage. "It works - ship it, and get on to the next thing" tends to be the approach. My point is that common behavior that COULD be reused and benefit from Traits is not usually identified until quite late in the game, after a lot of code has already been written, if it can be identified at all.
The other idea that I was trying to get across is that code reuse is a double-edged sword. While it can reduce maintenance effort, and improve the overall quality of a code base, it also makes the codebase more brittle by introducing heavily loaded single points of failure.
So I guess I am raising a largely philosophical issue. As I understand it, Traits facilitates code reuse in ways that would be difficult if at all possible with a single inheritance class hierarchy. This capability comes at the cost of an extra layer of complexity (or degree of freedom, if you prefer) and possibly a decrease in performance. The philosophical questions are how can I use it, and how will I benefit from having used it?
The Collection hierarchy example shows that I can implement 27 classes with 48 Traits, saving about 10% in the number of methods. This says to me that there was only an average of 2 or 3 methods per class that were redundant or refactorable (Given that we end up with 567 methods, this implies 630 methods in the original implementation, so we eliminated about 63 methods). So, in this respect I don't think that the Collection hierachy is a very strong example for showing the benefits of Traits. You had my attention more with the RectangleMorph example. There you were going to save 70 methods with only 3 classes involved.
Admittedly, the paper that is dedicated to the Traits based Collection class hierarchy goes into more detail and shows a greater savings in method count, but I am not sure if I agree that counting (m+h) is legitimate, so I will call it 17.7% instead of 28.2%.
I did read the papers, but like many good papers they generate at least as many questions as answers. Traits is very "blue plane" stuff and therefore interesting, but we've had single inheritance for over thirty years, and most of the world still doesn't take advantage of the capability that it brings. I approach Traits with trepidation because it offers another way to do things and I do think there is such a thing as too much flexibility. That was/is one of the major problems with C++.
So I guess I'm still looking for somebody to show me the "good-ness" of Traits, because so far it looks interesting, but like a lot of work for a small increase in code reuse and a (hopefully) small decrease in performance, and we've been seeing a "small" decrease in performance with each successive version of Squeak for way too long now. This is (of course), only my opinion. I could certainly be in the minority here.
Traits shows clear value in refactoring, but refactoring is "code cleaning", and it doesn't happen much in the real world. In fact, it is sometimes "forbidden" because it is seen as a high risk to touch code that is "field proven".
So for now I will sit back, watch, and try to learn something.
-Dean
stéphane ducasse ducasse@iam.unibe.ch Sent by: squeak-dev-bounces@lists.squeakfoundation.org 08/30/2005 09:37 AM Please respond to The general-purpose Squeak developers list
To: The general-purpose Squeak developers list squeak-dev@lists.squeakfoundation.org cc: Subject: Re: Traits approaching mainstream Squeak
Hi dean
do you ***really*** think that the Collection hierarchy is a toy example.... I'm not sure that we are talking about the same.
On 30 août 05, at 02:28, Dean_Swan@Mitel.COM wrote:
While I find all this discussion fascinating, I would like to share a few thoughts on the idea of including Traits in mainstream Squeak.
My first concern is performance. Since Traits carry no state, they will need to use accessor methods and message sends are clearly much slower than direct instance variable access.
My second concern is regarding how Traits should/could/would be used. All of the examples that I have seen so far, including the refactoring of the Collection hierarchy, seem to me to be "toy" problems. I would be interested to read about non-trivial cases where Traits would solve a significant real world problem.
It would seem to me that the kind of reuse that Traits enables is the kind that isn't apparent at design time, since individual classes of object are usually designed separately and often by completely different people. The common behavior and opportunity for code reuse might only become apparent after the initial design is implemented. It has been my experience that once something is implemented and working, unless there is a compelling reason to justify it, the code is never revisited. Management is generally focused on allocating resources to things that will yield either an opportunity for increased revenues, or reduced costs, and code "cleaning" is rarely viewed as either. If it ever gets done (code cleaning), it is usually silently piggybacked on required bug fixes by individual developers who feel it is important. Am I in the minority here, or is this how commercial software development works in general?
Cleaning your design does not solve the problem that traits solve. Read the papers. Sometimes we are forced to duplicate code or to write a lot of delegate methods just because we cannot simply reuse method dictionary. This is what traits are about.
I would even suggest that single inheritance doesn't get used that much in practice. I see an awful lot of C++ where classes are root classes and implement a singleton object. I see poly-morphism used a lot, but not much inheritance. I also see STL used a lot to get common syntax container objects, that you get with the standard Smalltalk Collection hierarchy anyway.
So I guess I don't see what Traits gets us that we can't already do in Squeak with some judicious use of proxies, DNU and separate "behavior only" and "state only" classes using accessors for all instance variable access. Is the real benefit in having tools that formalize this and make it easy?
Is Traits implemented by just pointing a class's method dictionary entries to the approprate seemingly class-less compiled method defined in a Trait?
I guess I don't fundamentally oppose including Traits in mainstream Squeak, as long as it's still possible to ignore it and it doesn't cause a decrease in performance for commonly used objects (i.e. the Collection hierarchy). From what I've read in the whitepapers, it seems it should be safe and easy to ignore, so the only question I guess would be performance.
And lastly I will just say that as others (Andreas) have pointed out, maximising code reuse is not always desirable. I can see the argument in favor of code re-use to propagate common behavior without having to find every duplicated variation, but there is also the other side of the argument where a single bug in a common, highly reused method can cause a lot of things to break that might otherwise work properly.
-Dean
On 8/31/05, Dean_Swan@mitel.com Dean_Swan@mitel.com wrote:
I work on a product that is built from over ten thousand source files and has hundreds of developers working on it. [...]
I think what I am describing here is how a lot of software gets created in the real world [...]
Not where I live. I typically quit these jobs, probably ;-). I'm dying for Traits (ok, at the moment in VisualAge because they would make refactoring some existing code better). Refactoring is my daily bread and butter, and language enhancements that can give me new ways of refactoring are a big step forward (let alone language enhancements that give me new ways to think about new stuff I'm creating).
We made a sort of 'real world soup' of Squeak code. The biggest challenge the community faces is to keep it all maintainable. Traits, IMNSHO, will be a very important tool here.
On 31 août 05, at 02:21, Dean_Swan@Mitel.COM wrote:
Hi Stéphane,
Yes, I ***really*** do think that the Collection hierarchy is a "toy" example. Allow me to explain why:
What was done with the Collection hierarchy was essentially a refactoring to use Traits. It wasn't a new design from requirements. And while the Collection hierachy is a fabulous and powerful invention, it is really just a bunch of generic components to be used in building more complex systems.
My point was that I don't think that the capabilities Traits offers matches up with the way that commercial software is created in the "real" world.
I work on a product that is built from over ten thousand source files and has hundreds of developers working on it. The system runs on at least 8 different target CPU's (obviously, not all of the code runs on all eight different CPU types), and includes code written in C, C++, Java, JavaScript, Pascal, various assembly languages, and includes over 300 megabytes of executable code. I am not commenting on the quality of code, only the quantity here. The quality level of the code by any objective standards varies widely, depending on the skill and experience of the people who worked on it and the other constraints placed on the development (i.e. if we can't demonstrate the new feature to an important customer by the end of the (pick some time interval - quarter, month, week, etc.) we will lose a sale worth millions to an evil competitor).
Did we say that traits will solve all the problems? Traits support a better factoring of code and reuse within and among classes.
I think what I am describing here is how a lot of software gets created in the real world, and in this kind of environment the code never gets past the "make it work" stage. "It works - ship it, and get on to the next thing" tends to be the approach. My point is that common behavior that COULD be reused and benefit from Traits is not usually identified until quite late in the game, after a lot of code has already been written, if it can be identified at all.
then?
The other idea that I was trying to get across is that code reuse is a double-edged sword. While it can reduce maintenance effort, and improve the overall quality of a code base, it also makes the codebase more brittle by introducing heavily loaded single points of failure.
I do not buy that. I know a company that duplicated 3 millions of C++ code 15 times and they are in trouble.
So I guess I am raising a largely philosophical issue. As I understand it, Traits facilitates code reuse in ways that would be difficult if at all possible with a single inheritance class hierarchy. This capability comes at the cost of an extra layer of complexity (or degree of freedom, if you prefer) and possibly a decrease in performance. The philosophical questions are how can I use it, and how will I benefit from having used it?
The Collection hierarchy example shows that I can implement 27 classes with 48 Traits, saving about 10% in the number of methods. This says to me that there was only an average of 2 or 3 methods per class that were redundant or refactorable (Given that we end up with 567 methods, this implies 630 methods in the original implementation, so we eliminated about 63 methods). So, in this respect I don't think that the Collection hierachy is a very strong example for showing the benefits of Traits. You had my attention more with the RectangleMorph example. There you were going to save 70 methods with only 3 classes involved.
What can I say? You can use Smalltalk as it was 20 years ago. You can also use a trait image without using traits.
Admittedly, the paper that is dedicated to the Traits based Collection class hierarchy goes into more detail and shows a greater savings in method count, but I am not sure if I agree that counting (m+h) is legitimate, so I will call it 17.7% instead of 28.2%.
I did read the papers, but like many good papers they generate at least as many questions as answers. Traits is very "blue plane" stuff and therefore interesting, but we've had single inheritance for over thirty years, and most of the world still doesn't take advantage of the capability that it brings. I approach Traits with trepidation because it offers another way to do things and I do think there is such a thing as too much flexibility. That was/is one of the major problems with C++.
C++ is not flexible it is complex, complex and complex.
So I guess I'm still looking for somebody to show me the "good- ness" of Traits, because so far it looks interesting, but like a lot of work for a small increase in code reuse and a (hopefully) small decrease in performance, and we've been seeing a "small" decrease in performance with each successive version of Squeak for way too long now. This is (of course), only my opinion. I could certainly be in the minority here.
On my code there is no slowdown since I use accessor anyway. So the only slowdown you can get is getting an acccessor call instead of a direct access for an instance variable.
Traits shows clear value in refactoring, but refactoring is "code cleaning", and it doesn't happen much in the real world. In fact, it is sometimes "forbidden" because it is seen as a high risk to touch code that is "field proven".
So what you are saying is that we shoudl not do anything. So with that state of mind do you think that we would programming in OOP today or still in assembly.
So for now I will sit back, watch, and try to learn something.
-Dean
stéphane ducasse ducasse@iam.unibe.ch Sent by: squeak-dev-bounces@lists.squeakfoundation.org 08/30/2005 09:37 AM Please respond to The general-purpose Squeak developers list
To: The general-purpose Squeak developers list
squeak-dev@lists.squeakfoundation.org cc: Subject: Re: Traits approaching mainstream Squeak
Hi dean
do you ***really*** think that the Collection hierarchy is a toy example.... I'm not sure that we are talking about the same.
On 30 août 05, at 02:28, Dean_Swan@Mitel.COM wrote:
While I find all this discussion fascinating, I would like to share a few thoughts on the idea of including Traits in mainstream Squeak.
My first concern is performance. Since Traits carry no state, they will need to use accessor methods and message sends are clearly much slower than direct instance variable access.
My second concern is regarding how Traits should/could/would be used. All of the examples that I have seen so far, including the refactoring of the Collection hierarchy, seem to me to be "toy" problems. I would be interested to read about non-trivial cases where Traits would solve a significant real world problem.
It would seem to me that the kind of reuse that Traits enables is the kind that isn't apparent at design time, since individual classes of object are usually designed separately and often by completely different people. The common behavior and opportunity for code reuse might only become apparent after the initial design is implemented. It has been my experience that once something is implemented and working, unless there is a compelling reason to justify it, the code is never revisited. Management is generally focused on allocating resources to things that will yield either an opportunity for increased revenues, or reduced costs, and code "cleaning" is rarely viewed as either. If it ever gets done (code cleaning), it is usually silently piggybacked on required bug fixes by individual developers who feel it is important. Am I in the minority here, or is this how commercial software development works in general?
Cleaning your design does not solve the problem that traits solve. Read the papers. Sometimes we are forced to duplicate code or to write a lot of delegate methods just because we cannot simply reuse method dictionary. This is what traits are about.
I would even suggest that single inheritance doesn't get used that much in practice. I see an awful lot of C++ where classes are root classes and implement a singleton object. I see poly-morphism used a lot, but not much inheritance. I also see STL used a lot to get common syntax container objects, that you get with the standard Smalltalk Collection hierarchy anyway.
So I guess I don't see what Traits gets us that we can't already do in Squeak with some judicious use of proxies, DNU and separate "behavior only" and "state only" classes using accessors for all instance variable access. Is the real benefit in having tools that formalize this and make it easy?
Is Traits implemented by just pointing a class's method dictionary entries to the approprate seemingly class-less compiled method defined in a Trait?
I guess I don't fundamentally oppose including Traits in mainstream Squeak, as long as it's still possible to ignore it and it doesn't cause a decrease in performance for commonly used objects (i.e. the Collection hierarchy). From what I've read in the whitepapers, it seems it should be safe and easy to ignore, so the only question I guess would be performance.
And lastly I will just say that as others (Andreas) have pointed out, maximising code reuse is not always desirable. I can see the argument in favor of code re-use to propagate common behavior without having to find every duplicated variation, but there is also the other side of the argument where a single bug in a common, highly reused method can cause a lot of things to break that might otherwise work properly.
-Dean
Dean_Swan@Mitel.COM wrote: [snip]
The other idea that I was trying to get across is that code reuse is a double-edged sword. While it can reduce maintenance effort, and improve the overall quality of a code base, it also makes the codebase more brittle by introducing heavily loaded single points of failure.
This doesn't make sense to me. Increases quality and makes more brittle.
I would think that better quality code... More readable, understandable code... Potentially smaller set of code...
Would lead to more robust and less brittle.
Now as to single point of failure. Uh, maybe. But find and fix and it then should be fixed. And again leading to more robust.
[snip]
So I guess I'm still looking for somebody to show me the "good-ness" of Traits, because so far it looks interesting, but like a lot of work for a small increase in code reuse and a (hopefully) small decrease in performance, and we've been seeing a "small" decrease in performance with each successive version of Squeak for way too long now. This is (of course), only my opinion. I could certainly be in the minority here.
Traits shows clear value in refactoring, but refactoring is "code cleaning", and it doesn't happen much in the real world. In fact, it is sometimes "forbidden" because it is seen as a high risk to touch code that is "field proven".
[snip]
Now, I have no real world (commercial) development experience. I play with Squeak as my preferred environment for my projects. So with that disclaimer, take what I say for what you paid. :)
Squeak has had 20-30... years of single inheritance experience in it. How much of Squeak's code is older than your project? How much of Squeak's code is older than developers on your project? (Rhetorical Qs)
The point is that Squeak is a long lived, malleable, living program. Much is spoken of the cruftiness or uncleanness or parts of Squeak. This is despite the fact or due to the fact that it is so long lived. In this place and this situation, improved refactorability would be a great asset. It seems to me that is greatly desired by the users and developers of Squeak that it be refactored so that the original vision as expressed by Dan Ingalls and as stated by you here in this message: http://lists.squeakfoundation.org/pipermail/squeak-dev/2000-April/000775.htm...
""" I personally am opposed to gratuitous creation of new classes. I think it is contrary to one of Dan Ingalls' original design principles of making the whole system simple enough to be understood by a single person. Squeak already defines about 1200 different classes in the base image, which I think is an awful lot of different "kinds of things" to understand. """
I don't know, but maybe Traits can help with the problem you describe above. Maybe in introducing the flexibility of Traits we can reduce some bloat without reducing features and functionality.
I can only speak from my experience. But I constantly refactor my code. Why, because I seldom get it right the first time. I write the code and then run the code. Frequently it doesn't behave as I thought in my mind. Why, because my understanding of the problem was incomplete. As my understanding grows, I change, modify and refactor my code. That may or may not be very professional, I can't say. But I don't think it is too uncommon. Squeak makes such a process less painful. Traits may further aid such processes.
As for C++, it isn't Squeak. It isn't alive. Its frozen. C++ seems to me in its adding of flexibility added complexity. Here Traits seek to add flexibility while increasing simplicity.
I can't speak for your project. But it doesn't seem like simplicity, agility, or understandability of the system is a priority. Hopefully it is so for Squeak. And thus I speak my case as I understand it for Traits.
I would think that many, many, many commercial projects would benefit greatly by many of these practices which simplify and refactor code. Code seems to often live longer than expected and often having unexpected consequences. Refactoring and having clean code is of great value. Or at least it should be.
I like Squeak because it is a living, organic system. I have used too much dead software. Software that was fixed, frozen and unmalleable. Incapable of doing what I wanted because the program had no vision. Oh that all my software was in something like Squeak.
Enough ramblings. My apologies for the run-on-ramblings. ;)
Jimmie
On 31 août 05, at 21:25, Jimmie Houchin wrote:
Dean_Swan@Mitel.COM wrote: [snip]
The other idea that I was trying to get across is that code reuse is a double-edged sword. While it can reduce maintenance effort, and improve the overall quality of a code base, it also makes the codebase more brittle by introducing heavily loaded single points of failure.
This doesn't make sense to me. Increases quality and makes more brittle.
I would think that better quality code... More readable, understandable code... Potentially smaller set of code...
Would lead to more robust and less brittle.
Now as to single point of failure. Uh, maybe. But find and fix and it then should be fixed. And again leading to more robust.
same feeling here.
[snip]
So I guess I'm still looking for somebody to show me the "good- ness" of Traits, because so far it looks interesting, but like a lot of work for a small increase in code reuse and a (hopefully) small decrease in performance, and we've been seeing a "small" decrease in performance with each successive version of Squeak for way too long now. This is (of course), only my opinion. I could certainly be in the minority here. Traits shows clear value in refactoring, but refactoring is "code cleaning", and it doesn't happen much in the real world. In fact, it is sometimes "forbidden" because it is seen as a high risk to touch code that is "field proven".
[snip]
Now, I have no real world (commercial) development experience. I play with Squeak as my preferred environment for my projects. So with that disclaimer, take what I say for what you paid. :)
Squeak has had 20-30... years of single inheritance experience in it. How much of Squeak's code is older than your project? How much of Squeak's code is older than developers on your project? (Rhetorical Qs)
The point is that Squeak is a long lived, malleable, living program. Much is spoken of the cruftiness or uncleanness or parts of Squeak. This is despite the fact or due to the fact that it is so long lived. In this place and this situation, improved refactorability would be a great asset. It seems to me that is greatly desired by the users and developers of Squeak that it be refactored so that the original vision as expressed by Dan Ingalls and as stated by you here in this message: http://lists.squeakfoundation.org/pipermail/squeak-dev/2000-April/ 000775.html
""" I personally am opposed to gratuitous creation of new classes. I think it is contrary to one of Dan Ingalls' original design principles of making the whole system simple enough to be understood by a single person. Squeak already defines about 1200 different classes in the base image, which I think is an awful lot of different "kinds of things" to understand. """
nobody is for creating classes for the sake of it (even if we introduce Beeper :). Now a class is an abstraction and having 3 classes instead of a large a difficult to read one is much better to help you to understand.
For example: why halospec creation methods are defined on preference class and not on Halospec this is just one examples.
I don't know, but maybe Traits can help with the problem you describe above. Maybe in introducing the flexibility of Traits we can reduce some bloat without reducing features and functionality.
I can only speak from my experience. But I constantly refactor my code.
me too.
Why, because I seldom get it right the first time. I write the code and then run the code. Frequently it doesn't behave as I thought in my mind. Why, because my understanding of the problem was incomplete. As my understanding grows, I change, modify and refactor my code. That may or may not be very professional, I can't say. But I don't think it is too uncommon. Squeak makes such a process less painful. Traits may further aid such processes.
same here. Hence the importance of the RB engine because if refactoring takes one 10th of a second then you do it. if it takes 5 min. then you don't.
As for C++, it isn't Squeak. It isn't alive. Its frozen. C++ seems to me in its adding of flexibility added complexity. Here Traits seek to add flexibility while increasing simplicity.
I can't speak for your project. But it doesn't seem like simplicity, agility, or understandability of the system is a priority. Hopefully it is so for Squeak. And thus I speak my case as I understand it for Traits.
us too. even if as I said in my exhcanges with andreas. Sometimes I would favor readability over fine-grained reuse.
I would think that many, many, many commercial projects would benefit greatly by many of these practices which simplify and refactor code. Code seems to often live longer than expected and often having unexpected consequences. Refactoring and having clean code is of great value. Or at least it should be.
I like Squeak because it is a living, organic system. I have used too much dead software. Software that was fixed, frozen and unmalleable. Incapable of doing what I wanted because the program had no vision. Oh that all my software was in something like Squeak.
Enough ramblings. My apologies for the run-on-ramblings. ;)
:)
Jimmie
Jimmie Houchin wrote:
Dean_Swan@Mitel.COM wrote: [snip]
The other idea that I was trying to get across is that code reuse is a double-edged sword. While it can reduce maintenance effort, and improve the overall quality of a code base, it also makes the codebase more brittle by introducing heavily loaded single points of failure.
This doesn't make sense to me. Increases quality and makes more brittle.
I would think that better quality code... More readable, understandable code... Potentially smaller set of code...
Would lead to more robust and less brittle.
Now as to single point of failure. Uh, maybe. But find and fix and it then should be fixed. And again leading to more robust.
You are both right here taken another dimension into account: control over your code or not.
Inside one component under your control you should avoid code duplication. For me detecting code duplication in principle suggests to create a shareable entity (Class, method, block, Trait (if there)). This said besides the problems tackled by Traits, of course.
But if your component depends on an external component being in a sufficient stable state: this could be a sign to store this external component in exactly this state. Newer versions may or may not work with your component for whatever reason! If it later will be changed, the changed version may be necessary in your system too (both being there made possible e.g. by renaming the old one), to keep newer components - made by you or others - running. Here you end in an extreme case of code duplication!
Examples -------- - You have detected a bug in another component and programmed a workaround. Later a fixing of this bug may break your workaround! Inspite of beeing the fix more 'correct'. - You may not have the time to keep in sync with the improvements of external components you need (to take the positive side of changes of external components, there are more), and the external components used by you are good enough. - From another world: your Java app works with many libs in their versions. After a while you try to update all these libs to their newest state, start your app and something is broken. It may be reasonable just to stop this trial and switch back to all of the older versions...
Regards, Stephan
...
squeak-dev@lists.squeakfoundation.org