Copy of base method in derived class tricks debuger

I have classes A and B, B derived from A, A has method Abc.

From INT of class B I see that compiler copies implementation of Abc to class B, so that Abc exists both in A and B.

As result, when B invokes Abs, B.Abs() is executed instead of A.Abs(). In result debuger is not able to step into Abs and breakpoints in A.Abs never hit.

Why this happens and how can I avoid this?

Update:

OK, now I know the reason: compiler makes the copy if Abc has this line:

cn=##Expression($$$quote(%classname))

hmmmm... compiler needs name of method's class so it "moves" the method to child class. Well, perhaps there is a good reason for that but for the moment the solution looks strange.

I need classname (and %methodname) to provide location to my macro throwing exception in certain conditions. Seems I have to drop that unless someone knows a way how to avoid the copying in this case.

 

  • 0
  • 0
  • 201
  • 15
  • 4

Answers

Use ##SafeExpression instead of ##Expression to generate code once.

Indeed, the documentation of ##Expression describes the behaviour and ##SafeExpression avoids the copying.

Many thanks, Eduard!

##SafeExpression will not work for you.

The method Abs() will get baked into A with the class name A.

B will no longer get its own baked method, so when Abs() is called on B, it will incorrectly return A.

That's perfectly OK for my objective: all I need, is just a text like "location of your exception is <location>". Will <location> be A.Abc or B.Abc doesn't really matter.

Just wondering if you are missing a trick here.

If you are using try catch then your catch will return %Exception.AbstractException, this has a Location property.

It will but with two nuances:

^%oddENV("callererrorinfo") must be set

- the format could be a bit cryptic, like 

Location = "zrun+3^digi.test.main.1"

while my home made location will says "assertion XYZ failed in digi.test.mai.run"

BTW: can you tell what UI/api is supposes for setting values of ^%oddENV, in particular "callererrorinfo"?

 

 

here is one real example of my self backed location:

<EXCEPTION>
assertion failed: digi.chimport.debugMakeStatus: invalid param: 'acc' stack:
zthrowif+2^digi.core.AssertException.1 +1
zdebugMakeStatus+7^digi.chimport.1 +1
ztestChImport+43^digi.test.main.1 +1
%DispatchClassMethod+8^digi.test.framework.1 +1
zdoall+11^digi.test.main.1 +1
zrun+3^digi.test.main.1 +1
zDebugStub+30^%Debugger.System.1 +2
</EXCEPTION>

 

 

I guess you could override the Abs method in your B class and make the override code simply call the superclass's method using ##super.

Documentation of ##super is here.

I did this test before posting my question to see if the overloading stops the copying.  It does stop and I see compiler generates code like 

##class(A)$this.Abc()

but  this way can not be seen as solution because this trick must be done for each such method in each derived class
 

 

Please help me understand why it is important to you that the debugging goes through the code in A's INT routine rather than the equivalent code in B's INT routine.

John,  because of debugging:

- you set breakpoint in A.Abc() but it never hit because cache executes B.Abc()

- because of some reason, debuger is not able to step in nether of the copies

As an alternative to...

   s cn=##Expression($$$quote(%classname))

You could just do...

  cn=$CLASSNAME()

 

I had a problem with $classname in some situations but I'll recheck it. Thank you.

Comments

I think we need to see your source code.

If you are on 2016 then the parent code should not be transcompiled into your child class INT code unless there is some dynamic compile challenge to your code.