debugger problem using ##(...)

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

debugger problem using ##(...)

ar-2
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?


Reply | Threaded
Open this post in threaded view
|

Re: debugger problem using ##(...)

Blair McGlashan
"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
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?
>

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


Reply | Threaded
Open this post in threaded view
|

Re: debugger problem using ##(...)

ar-2
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
>


Reply | Threaded
Open this post in threaded view
|

Re: debugger problem using ##(...)

Blair McGlashan
"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


Reply | Threaded
Open this post in threaded view
|

Re: debugger problem using ##(...)

Chris Uppal-3
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


Reply | Threaded
Open this post in threaded view
|

Re: debugger problem using ##(...)

Blair McGlashan
"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
less
> 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


Reply | Threaded
Open this post in threaded view
|

Re: debugger problem using ##(...)

Eliot Miranda
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


Reply | Threaded
Open this post in threaded view
|

Re: debugger problem using ##(...)

Blair McGlashan
"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