Hi,
I'm starting a new thread, but it is really a continuation under a different name of Bill's thread, '#browseDefinitionsOf: includes redundant item - time to panic?', from a couple of weeks back. Ian, Bill, and I, have all seen a situation where you can end up with two classes with the same name. That's to say that the Smalltalk dictionary includes only one of them, but the subclasses list(s) of their parent class (and metaclass's parent) includes two Class objects with the same name. I've tried to reproduce it, and had found what seemed to be a nice reproducible test case. However, stepping through the code did /not/ show the bug. And -- worse -- as I was writing up a post describing it, it stopped "working" altogether (the bug vanished) and I can't reproduce it at all now (so some of the description below is from memory, unfortunately). Basically, the problem is that evaluating an expression that removes instvars, and thus leaves some methods with syntax errors, can result in two versions of the class existing at once. It has shown up for all of us when using the Chunk Browser, but it isn't the CB's fault. It can be reproduced just by evaluating class creation expressions in a workspace. As far as I could tell, it /had/ to be evaluated like that (or in the environment that the CB sets up) for the bug to manifest. Oddly (but perhaps coincidentally) I couldn't get it to fail when just filing-in the equivalent expression. Anyway, to (try to) reproduce: Work in a throwaway image! Create a class AAATemp. Create a fileout of that class, AAATemp.cls (you may as well edit it to remove the GUID declaration, etc, since only the class creation expression will be needed). Add an instvar, 'var' to that class, and a method that accesses it: aMethod ^ var. Save your image at this point, everything we do hereafter is awkward to reverse and what we've done is tedious to recreate. Now evaluate the following in a workspace: Object subclass: #AAATemp instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' classInstanceVariableNames: '' (which is just a normal class definition expression, of course) and open a new CHB. If the demo has "worked" there should now be two classes called AAATemp (you do have to open a new CHB, any existing ones don't update). Exit that image without saving, and restart (thus backing up to just before the point where we evaluated the expression). This time try filing in 'AAATemp.cls' which will evaluate a class-creation method just like the above. If your experience is the same as mine, then this will work correctly. Can anyone re-create this ? -- chris |
On Thu, 16 Dec 2004 10:28:47 -0000, Chris Uppal
<[hidden email]> wrote: > Can anyone re-create this ? I can't, on a 5.1.4 fresh image. In both cases, I only see 1 AAATemp class in the new CHB, which no "var" defined. -- Regards HweeBoon MotionObj |
In reply to this post by Chris Uppal-3
Chris,
The following works reliably - is it connected to your example? Create a class AAATemp with one instVar (as in your example). Then, in a workspace, evaluate (either together or one statement at a time) ... Smalltalk at: #AAATemp put: nil. Object subclass: #AAATemp instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' classInstanceVariableNames: '' Opening up a CB shows two AAATemp classes, one with an instVar and one without. It raises a couple of questions about globals that aren't classes -- Ian Use the Reply-To address to contact me. Mail sent to the From address is ignored. |
I wrote...
> without. It raises a couple of questions about globals that aren't > classes No it doesn't :-). A class (Object in this case) caches it's subclasses and removing #AAATemp from the SystemDictionary in this way doesn't remove it from #Object's cache. As the original class object still has hard references, from #Objects classes instVar, it is not garbage collected and remains available - albeit not from the SystemDictionary. #Object's classes instVar now contains two valid #AAATemp objects so when the ClassBrowser is opened both are displayed. Motto - Don't nil out classes in the SystemDictionary, use #removeFromSystem instead. -- Ian Use the Reply-To address to contact me. Mail sent to the From address is ignored. " |
Ian,
> Motto - Don't nil out classes in the SystemDictionary, use #removeFromSystem > instead. Dumb question: does this affect only your example, or does it perhaps get to the bottom of the problem? Could you, Chris, and I be falling into the same trap? Indirectly? In addition to your CB, I spend a fair amount of time running my code generator and friends. Chris, we hinted slightly at the possibility of a tool that would detect, and maybe even be able to undo the "damage". Is that something we could/should try to build? If it can tell which is the redundant class, perhaps it could file out all of its methods prior to removing it; otherwise, it could file out everything and offer expressions to help the user remove one of the other class. If we are reasonably certain the CB is indeed innocent in this, perhaps it could be used to simplify browsing the suspect methods. Have a good one, Bill -- Wilhelm K. Schwab, Ph.D. [hidden email] |
In reply to this post by Yar Hwee Boon-3
Yar Hwee Boon wrote:
> > Can anyone re-create this ? > > I can't, on a 5.1.4 fresh image. In both cases, I only see 1 AAATemp class > in the new CHB, which no "var" defined. Thank you for trying. This is definitely an odd one... -- chris |
In reply to this post by Schwab,Wilhelm K
Bill,
> > Motto - Don't nil out classes in the SystemDictionary, use > > #removeFromSystem instead. > > Dumb question: does this affect only your example, or does it perhaps > get to the bottom of the problem? Could you, Chris, and I be falling > into the same trap? Indirectly? I don't believe so. My workspace expression doesn't go anywhere near the system dict (except insofar as the class builder does it, but that's where the bug must lie -- in some sense). > Chris, we hinted slightly at the possibility of a tool that would > detect, and maybe even be able to undo the "damage". Is that something > we could/should try to build? A workspace expression to detect such occurrences is easy enough. classes := Class allSubinstances. names := (classes collect: [:each | each name]) asBag. odd := classes select: [:each | (names occurrencesOf: each name) > 1] A few workspace expressions to fix-up the damage could be worked out too, based on Class>>removeFromSuper and Class>>fileOutOn:. (Remembering to check that the duplicate classes had duplicate metaclasses before fixing the metaclasses) The problem (which would be especially severe for a proper tool) is how to test it ? I wouldn't be happy using a tool that grubbed around in the bowels of my image[*] unless I knew it had received /lots/ of testing. But how do we test it when we can't reproduce the bug ? And if we /could/ reproduce the bug, then I'm sure OA would fix it easily enough. Still, there is /some/ good news -- I've just managed to reproduce it again in the throwaway image I was using for testing, so there's hope of pinning it down yet. I don't have time to do anything more today, but I'll investigate more later. ([*] it could be that the phrase "grubbed around in the bowels of my image" has never been used before by mortal man ;-) Google doesn't find any match, but it does ask if I'm "Looking for pictures?" -- thanks, but no!) > If we are reasonably certain the CB is indeed innocent in this, I really can't think of any way that the CB could be implicated. I currently /suspect/ that its an innocent victim of some semi-deterministic interaction between the environment where an expression is evaluated and the handlers for the various kinds of compilation Exception. But that's just a suspicion. -- chris |
In reply to this post by Schwab,Wilhelm K
Bill,
> Dumb question: does this affect only your example, or does it perhaps get > to the bottom of the problem? Could you, Chris, and I be falling into the > same trap? Indirectly? Probably not, but I think it /might/ help narrow down where any problem /may/ occur. I spent a bit of time going though the what happens to the #subclasses collection in a classes superclass when you modify the classes definition. A precis .... A new modified subclass is created. The new class is added to its superclasses #subclasses collection (which now contains two different versions of the same subclass). *A lot goes on - including recompiling all the methods in the class. The old class is removed from the superclasses #subclasses collection. If something untoward should happen in the line with the asterisk, causing an abort in the process, then it is /possible/ that we could end up with a superclass that a browser shows as having two classes with the same name. As to what could cause the abort.... <shrug> -- Ian Use the Reply-To address to contact me. Mail sent to the From address is ignored. |
Ian, Bill,
> I spent a bit of time going though the what happens to the #subclasses > collection in a classes superclass when you modify the classes definition. > A precis .... > > A new modified subclass is created. > The new class is added to its superclasses #subclasses collection (which > now contains two different versions of the same subclass). > *A lot goes on - including recompiling all the methods in the class. I've found that my original example exhibits the bug reliably when I load the .cls file via the chunk browser. The problem seems to be that ChunkBrowserExpressionChunk>>restoreAndLog: consumes the error notification, thus aborting the intermediate processing. Adding e pass to the handler block seems to avoid the problem; I don't have the slightest idea whether that's the "right" way to do it, though. (There may be a similar problem with ChunkBrowserMethodDefinitionChunk>>restore, but I'm not sure about that either.) I still don't know why my workspace expression showed the bug for a while, then stopped. But since I /still/ can't make it "work" again, I've given up and shall put it down to some unknown (and unknowable) error on my part. -- chris |
Free forum by Nabble | Edit this page |