Written by

Question Arto Alatalo · Apr 11, 2017

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.

Comments

Arto Alatalo  Apr 11, 2017 to John Murray

Cache for Windows (x86-64) 2016.1.1

0
Sean Connelly  Apr 11, 2017 to Arto Alatalo

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.

0
Arto Alatalo  Apr 11, 2017 to Sean Connelly

Please check my update. Any comments?

0
John Murray · Apr 11, 2017

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.

0
Arto Alatalo  Apr 11, 2017 to John Murray

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
 

0
John Murray  Apr 11, 2017 to Arto Alatalo

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.

0
Arto Alatalo  Apr 11, 2017 to John Murray

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

0
Arto Alatalo  Apr 12, 2017 to Eduard Lebedyuk

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

Many thanks, Eduard!

0
Sean Connelly  Apr 12, 2017 to Arto Alatalo

##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.

0
Arto Alatalo  Apr 12, 2017 to Sean Connelly

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.

0
Sean Connelly  Apr 12, 2017 to Arto Alatalo

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.

0
Arto Alatalo  Apr 12, 2017 to Sean Connelly

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

0
Arto Alatalo  Apr 12, 2017 to Arto Alatalo

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>

0
Arto Alatalo · Apr 12, 2017

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

Many thanks, Eduard!

0
Sean Connelly · Apr 12, 2017

As an alternative to...

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

You could just do...

  cn=$CLASSNAME()

0
Arto Alatalo  Apr 12, 2017 to Sean Connelly

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

0
Arto Alatalo · Apr 12, 2017

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

0