I encountered the following interesting debugger problem.
My source looks something like this: Function class>>myFunc1 ^ ##( Array with: #(myArg1 myArg2) with: [ : myArg1 : myArg2 | (Foo process: myArg1 with: myArg2) bar: PoolVarA]) The intent is to return a statically built array containing a block. This code works correctly but the debugger fails in CompiledExpression>>asDebugMethod (DNU sourceDescriptor) when stepping into the evaluation of the block, right after evaluating the (Foo process...) The error reported on the Transcript is: Error: Metaclass>>doIt at line nn: undeclared 'PoolVarA' I think the problem is that the methodClass of the compiledExpression created by ##(..) is Metaclass instead of Function (class?) . I also tried the cleaner ^#( #(myArg1 myArg2) ##( [ : myArg1 : myArg2 | .... ] )) to no avail. The following works around it. ^(formals funcBody) at: 1 put: #(myArg1 myArg2) ; at: 2 put: [ : myArg1 : myArg2 | ...]) ; yourself It still avoids the overhead of creating the array and the debugger is happy but there is a small cost of a few instructions (this is a very critical code section). The other (theoretical) objection is writing into the literal frame (even though it is fairly reentrant since the contents are entirely static. But it's probably not portable eg to an implementation which protected methods in it's code segment (wasn't there one, like VS/OS2 or something?)). I'm not sure, should the CompiledExpression have Function or Function class as it's methodClass? Or would that not be correct for some reason? |
"ar" <[hidden email]> wrote in message
news:+49hPNR=0MAhx5qdPxMMXs4i=[hidden email]... > I encountered the following interesting debugger problem. > > My source looks something like this: > > Function class>>myFunc1 > > ^ ##( Array > with: #(myArg1 myArg2) > with: [ : myArg1 : myArg2 | > (Foo process: myArg1 with: myArg2) bar: PoolVarA]) > > The intent is to return a statically built array containing a block. This > works correctly but the debugger fails in CompiledExpression>>asDebugMethod > (DNU sourceDescriptor) when stepping into the evaluation of the block, right > after evaluating the (Foo process...) > > The error reported on the Transcript is: > > Error: Metaclass>>doIt at line nn: undeclared 'PoolVarA' > > I think the problem is that the methodClass of the compiledExpression created > by ##(..) is Metaclass instead of Function (class?) . I also tried the cleaner > > ^#( #(myArg1 myArg2) ##( [ : myArg1 : myArg2 | .... ] )) > > to no avail. The following works around it. > > ^(formals funcBody) > at: 1 put: #(myArg1 myArg2) > ; at: 2 put: [ : myArg1 : myArg2 | ...]) > ; yourself > > It still avoids the overhead of creating the array and the debugger is > but there is a small cost of a few instructions (this is a very critical code > section). The other (theoretical) objection is writing into the literal frame > (even though it is fairly reentrant since the contents are entirely static. > But it's probably not portable eg to an implementation which protected methods > in it's code segment (wasn't there one, like VS/OS2 or something?)). > > I'm not sure, should the CompiledExpression have Function or Function class as > it's methodClass? Or would that not be correct for some reason? > When we originally implemented the ##() mechanism, we decided that the compilation context should be the class of the object in which one was compiling it. This was so that if one used 'self' in an instance side ##() expression, it could refer to something sensible (obviously it can't refer to the instance, since it doesn't exist), and the obvious choice was the class. Extrapolating from this we thought that the same should apply to methods compiled on the class side, and consequently these would be compiled in the context of the metaclass. So to summarise, if one compiles a method with a ##() expression in an instance side method of Object, then 'self' is 'Object' (the class). If, on the other hand, one compiles a method with a ##() expression in a class method of Object, then 'self' is 'Object class' (the metaclass). This seems "correct" and "consistent", but causes the problem that class side ##() expressions could not then refer to pool constants since there were really being compiled as 'methods' of Metaclass when on the class side. Therefore we tweeked the compiler to allow access to the pools. With the benefit of hindsight, we'd probably implement it differently (or not at all), but it is probably too long established to change now I'm afraid. I'll look into the Debugger issue though, so thanks for pointing it out. In general we would recommend avoiding the ##() mechanism, except, for example, as a way to calculate constants, or a way to deliberately achieve a static binding without directly referencing a class name. For most other uses we would recommend the use of a class variable instead. A particular problem with ##() is that the code run to calculate the literal value is not visible to the normal reference searching mechanisms. Also because the expression is statis in nature, one can easily overlook the fact that it has become outdated. Regards Blair |
Blair,
Thanks for the lore. I enjoy studying the implementation details as much I enjoy as hiding them :) There is always more than meets the eye.. I understand the 'too long established' reason for not touching it, but in the interest of theory at least, I'd like to push the following idea: The class side context to be the class, the same as on the instance side. I'd make these arguments: -For at least half the picture, (the class side) 'self' would refer to something which was completely natural. Eg, it would be the class just like in any other self reference. -A key objection might be the lack of symmetry with the instance side (Consistency issue). IMHO this is not too theoretically offensive. Class and instance are naturally asymmetric in this regard, since one has a natural and sensible context at compile time, the other doesnt. By nature the use of the construct would be for constants which are class-oriented in nature anyway. So they could share behavior. Analogously, there is only one set of Pools for both sides. Regardng consistency, now all self references would be fully consistent on the class side as previously mentioned. - It makes the compiler tweak go away (?) - It makes the debugger problem go away (?) (IMHE when a design change makes code shrink or problems go away, it tends to confirm the design) - The question of impact. Could anyone on the planet really be intending or depending on ##() in a class method using the metaclass as the context? Just a thought... alan r >When we originally implemented the ##() mechanism, we decided that the >compilation context should be the class of the object in which one was >compiling it. This was so that if one used 'self' in an instance side ##() >expression, it could refer to something sensible (obviously it can't refer >to the instance, since it doesn't exist), and the obvious choice was the >class. Extrapolating from this we thought that the same should apply to >methods compiled on the class side, and consequently these would be compiled >in the context of the metaclass. So to summarise, if one compiles a method >with a ##() expression in an instance side method of Object, then 'self' is >'Object' (the class). If, on the other hand, one compiles a method with a >##() expression in a class method of Object, then 'self' is 'Object class' > (the metaclass). This seems "correct" and "consistent", but causes the >problem that class side ##() expressions could not then refer to pool >constants since there were really being compiled as 'methods' of Metaclass >when on the class side. Therefore we tweeked the compiler to allow access to >the pools. > >With the benefit of hindsight, we'd probably implement it differently (or >not at all), but it is probably too long established to change now I'm >afraid. I'll look into the Debugger issue though, so thanks for pointing it >out. > >In general we would recommend avoiding the ##() mechanism, except, for >example, as a way to calculate constants, or a way to deliberately achieve a >static binding without directly referencing a class name. For most other >uses we would recommend the use of a class variable instead. A particular >problem with ##() is that the code run to calculate the literal value is not >visible to the normal reference searching mechanisms. Also because the >expression is statis in nature, one can easily overlook the fact that it has >become outdated. > >Regards > >Blair > |
"ar" <[hidden email]> wrote in message
news:[hidden email]... > Blair, > > Thanks for the lore. I enjoy studying the implementation details as much I > enjoy as hiding them :) There is always more than meets the eye.. > > I understand the 'too long established' reason for not touching it, but in the > interest of theory at least, I'd like to push the following idea: > > The class side context to be the class, the same as on the instance side. >... I meant to imply that as as more practical implementation in my previous post, but I don't think I mentioned it in the end. > ... > - The question of impact. Could anyone on the planet really be intending or > depending on ##() in a class method using the metaclass as the context? Almost certainly they don't really want to access the metaclass, but that is not the point. If they have attempted to access the class from class side methods then they may have done so in such a way that it would break should we change it. Having said that the most common form in the image as shipped looks like this: ##(self instanceClass blah blah) this wouldn't break because #instanceClass is implemented to return self in Class, as well as the sole instance implementation in Metaclass. So maybe it would be possible to change it without having too much impact. Anybody else have any opinions? In particular does anyone know how it operates in VisualAge? Regards Blair |
Blair,
> Anybody else have any opinions? In particular does anyone know how it > operates in VisualAge? VASt 5.5 evaluates ##(self) as the class on both the instance and class sides. Which seems like a reasonable choice to me. FWIW, my own image has no class side refs to ##(self) without sending #instanceClass to it. Suggests that the IBM behaviour (though strictly less logical) is more useful. Oh, while I'm thinking of it: "self" in the class comment pane of a CHB evaluates to the metaclass if the CHB is showing the class side. That's inconsistent with the behaviour of "self" evaluated from the method pane, which is always the class whether the CHB is showing the class or instance side (and which is what I'd expect). -- chris |
"Chris Uppal" <[hidden email]> wrote in message
news:[hidden email]... > Blair, > > > Anybody else have any opinions? In particular does anyone know how it > > operates in VisualAge? > > VASt 5.5 evaluates ##(self) as the class on both the instance and class > sides. > > Which seems like a reasonable choice to me. > > FWIW, my own image has no class side refs to ##(self) without sending > #instanceClass to it. Suggests that the IBM behaviour (though strictly > logical) is more useful. Yes, I agree. I have recorded a change request for it, and if trivial (I think it should be), we may be able to get it into 5.0. > Oh, while I'm thinking of it: "self" in the class comment pane of a CHB > evaluates to the metaclass if the CHB is showing the class side. That's > inconsistent with the behaviour of "self" evaluated from the method pane, > which is always the class whether the CHB is showing the class or instance > side (and which is what I'd expect). That has annoyed me a few times recently too, it too has been duly recorded. Regards Blair |
In reply to this post by Blair McGlashan
Blair McGlashan wrote:
[much snipped] > In general we would recommend avoiding the ##() mechanism, except, for > example, as a way to calculate constants, or a way to deliberately achieve a > static binding without directly referencing a class name. For most other > uses we would recommend the use of a class variable instead. A particular > problem with ##() is that the code run to calculate the literal value is not > visible to the normal reference searching mechanisms. Also because the > expression is statis in nature, one can easily overlook the fact that it has > become outdated. Blair, while I agree that the mechanism has its drawbacks its still attractive enough for people to want to use it despite them. When I implemented it in BrouHaHa I "fixed" the reference searching mechanism by including all the literals generated in compiling ##() expressions in the compiled method containing them. It adds an insignificant amount of bloat to methods but the cross-referencing is well worth it. -- _______________,,,^..^,,,____________________________ Eliot Miranda Smalltalk - Scene not herd |
"Eliot Miranda" <[hidden email]> wrote in message
news:[hidden email]... > > > Blair McGlashan wrote: > [much snipped] > > In general we would recommend avoiding the ##() mechanism, except, for > > example, as a way to calculate constants, or a way to deliberately achieve a > > static binding without directly referencing a class name. For most other > > uses we would recommend the use of a class variable instead. A particular > > problem with ##() is that the code run to calculate the literal value is not > > visible to the normal reference searching mechanisms. Also because the > > expression is statis in nature, one can easily overlook the fact that it has > > become outdated. > > Blair, > > while I agree that the mechanism has its drawbacks its still attractive > enough for people to want to use it despite them. When I implemented it > in BrouHaHa I "fixed" the reference searching mechanism by including all > the literals generated in compiling ##() expressions in the compiled > method containing them. It adds an insignificant amount of bloat to > methods but the cross-referencing is well worth it. > Yes, that is probably a good idea. I suppose that one's deployment technology could always go through and nil out unreferenced literals too so that it didn't bloat deployed applications (apart from the extra slots of course). Regards Blair |
Free forum by Nabble | Edit this page |