Modules

Alexandre Bergel bergel at iam.unibe.ch
Sun Feb 27 18:15:43 UTC 2005


Dealing with class extension is very subtle. Approaches taken by Selector Namespace, Classboxes and Virtual Classes rely on bounding the visibility of class extension: the one who defines a class extension is the only one to see it. Conflicts are easily avoided in that way...

Cheers,
Alexandre


On Sun, Feb 27, 2005 at 01:11:31AM -0500, Colin Putney wrote:
> 
> On Feb 26, 2005, at 11:20 PM, Florin Mateoc wrote:
> 
> >>We have two versions of a method, both with complete version history. 
> >>Because we have the version history, it doesn't really matter that 
> >>the two versions come from different packages, it's exactly the same 
> >>as merging two versions of the same package. So instead of one 
> >>version overriding the other, we do a merge. By comparing the method 
> >>histories we can decide if one version supersedes the other. That 
> >>would mean that it's an updated version of the other, which means we 
> >>can rely on the user's wisdom again. If the user changed the method 
> >>from one of the versions we have to the other one, he must know what 
> >>he's doing. Therefore we use which ever version the user has already 
> >>chosen.
> >
> >
> >I am sorry, but this is simply not true. A developer may choose, in a 
> >newer version of a class, to ignore some unrelated development, and 
> >stick to an older protocol, by including some older versions for some 
> >of the methods. This is not a made up example, I have encountered the 
> >situation quite often. You can easily have, as a simplistic example, 
> >PackageA>ClassB>methodC(version1),methodD(version2) and 
> >PackageE>ClassB>methodC(version2),methodD(version1). The automatic 
> >resolution will do the wrong thing, and it won't even inform the user.
> 
> Ok, let's get into this in excruciating detail, because it's not clear 
> to me why you think the above example cannot be resolved correctly. 
> Let's say I have the following program elements, drawn from your 
> example, with history.
> 
> PackageA
> 
> ClassB>>methodC.version1 (ancestors: version0)
> ClassB>>methodD.version2 (ancestors: version0, version1)
> ClassB>>MethodE.version1 (ancestors: version0)
> 
> PackageZ
> 
> ClassB>>methodC.version2 (ancestors: version0, version1)
> ClassB>>methodD.version1 (ancestors: version0)
> ClassB>>methodE.version2 (ancestors: version0)
> 
> Ok, so let's see what happens if we load both packages into the same 
> image. PackageA and PackageZ both define methodC, and they have 
> different definitions. So we've got to decide which version, if any, 
> will be in the image. The version in PackageA is called version1, and 
> it was derived from version0. The version in PackageZ is called 
> version2, and lists version1 as its ancestor. Therefore, version2 was 
> created by modifying version1. So we'll choose version2, from PackageZ.
> 
> MethodD has the reverse situation. PackageA's version is a descendent 
> of PackageZ's, so we'll choose version2 again, but this time from 
> PackageA.
> 
> MethodE presents a conflict. Both versions descend from a common 
> ancestor, but neither descends from the other. So we pop up a conflict 
> resolution window, and let the user decide what methodE should look 
> like when both packages are present. This results in a new version, 
> called version3. When we're done, the image looks like this:
> 
> ClassB>>methodC.version2 (ancestors: version0, version1)
> ClassB>>methodD.version2 (ancestors: version0, version1)
> ClassB>>methodE.version3 (ancestors: version0, version1, version2)
> 
> Now, you are correct to point out that, say, methodC.version2 might 
> have been developed in PackageZ without PackageA loaded, and so might 
> not work as PackageA expects. Perhaps we should indeed log to the 
> Transcript when a merge automatically resolves overlapping packages. 
> There is no *guarentee* that version2 will work right. But our chances 
> of success are better if we follow the intention of the developer of 
> version2, which was to replace version1. Following the order that 
> packages are loaded is little different than choosing at random.
> 
> >Making independently developed packages work together means 
> >(intelligent) work, and if there's any overlap, the chances of solving 
> >the issues automatically are, I believe, very slim, and versioning 
> >does not help. Even if all the common methods in one of the packages 
> >are newer versions (and descendants) of the same methods in the other 
> >packages, it still doesn't mean that they are made to work with the 
> >older package, it may simply mean that the newer package is supposed 
> >to work with a newer version of the older package. I think the only 
> >situation where you can say that there is no conflict is when the 
> >common methods are all identical, and for this you don't need 
> >versions. This is why, to my mind, overrides have nothing to do with 
> >versioning, they are simply a different kind of extension.
> 
> I agree that it takes intelligent work to make packages work together, 
> and I'm not suggesting that the computer can do that. I am suggesting 
> that, having done the work, we record the results so that we don't have 
> to do it again everytime we load those packages.
> 
> [snip]
> 
> >>>This is probably just the memory of a frustration with Envy: because 
> >>>it stores all these method editions (inluding every time you put a 
> >>>"halt" in a method), the noise level is pretty high, so I always 
> >>>wished that I could see at a glance, when looking at the list of 
> >>>editions for a method, which editions are "real". But even if we 
> >>>have explicit method versioning, so the noise is reduced, the most 
> >>>"real" ones are the ones associated with the holder's version, 
> >>>because there is an implicit minimal testing expectation for 
> >>>versions.For the method version I would expect something like a 
> >>>unit-test, for a class, the beginning of some functional testing. 
> >>>The expectation is even higher for the package, because it usually 
> >>>groups together classes working in tight coupling, so the testing 
> >>>done for a package version is more of a functional test, so now 
> >>>those methods "really" work. I guess it would be fun to disallow 
> >>>versioning if we detect that testing was not performed :) Seriously 
> >>>though, it might be interesting if we could link somehow versions to 
> >>>the tests performed.
> >>
> >>
> >>Ok, I see. You just want to define a group of program elements that 
> >>should be versioned together. With Monticello you do this explicitly, 
> >>so there's a lot less noise. Everything is a "real" version, and they 
> >>correspond to a bunch of other "real" versions that were current at 
> >>the same time.
> >
> >Even if you do it explicitely, not all versioning happens at the same 
> >time.
> >I develop a method, it looks good, I test it a little (workspace, 
> >unit-test, whatever), I am happy with it and I want to keep it. I 
> >version it (separately, because this is what method-level granularity 
> >means).
> 
> Interesting, because that's not what I mean by "method-level 
> granularity."
> 
> In MC1 (and Store, as far as I can tell), only packages have ancestry. 
> The ancestry of a method has to be reconstructed by examing all the 
> versions of the package it appears in and noting how it changes. In MC2 
> (and Envy, as far as I can tell), methods have individually recorded 
> ancestry. This is why I say that MC2 versions at method-level 
> granularity.
> 
> But that doesn't mean that you have to version new methods in 
> isolation, whether explicitly or with every accept as in Envy. If you 
> do that, you loose the spacial context I mentioned in my last post. 
> That version is just noise, so why bother? It's not like the method is 
> going anywhere. You can save your image without versioning it, and even 
> if you manage to crash the VM you can always pull it out of the change 
> log.
> 
> In MC1 you always version whole packages at a time. MC2 is more 
> flexible, in that you can specify other ways of separating the code you 
> are interested in from the rest of the image. But whatever your method 
> of segregation, you always version all of it at once. So in this sense, 
> Monticello versions at "project-level granularity," the project being 
> whatever you're working on, be it a package, change set or whatever. 
> It's important to do that so as to get the spacial context needed to 
> merge snapshots correctly.
> 
> Colin
> 
> 
> 

-- 
_,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:
Alexandre Bergel  http://www.iam.unibe.ch/~bergel
^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;._,.;:~^~:;.



More information about the Squeak-dev mailing list