Get call chain when inside a table form

I’m liking “Get call chain” which I’m only seeing now that we are working on v18. Much of our error handling code creates an automatic log entry into a table in our database, it was trivial add a call chain to the log so we can see the pathway to the problem.

However, I have to say that I’m a little disappointed that the function name does not include the table when including a form object method. I mocked up a (admittedly awful) minimal example where I open a related form from a master form. As you can clearly see, 4D’s debugger can see the table, but that knowledge is not included in “Get call chain”.

The problem comes when one table form opens a table form from a different table. This is a very normal workflow for us, since our database is very old, and much of it uses the “input form” “output form” workflow.

Assume that “SetCallChain” is my error handler. As you can clearly see from the image, there is no way for the error handler to know the table source of the first form. I could probably wire up some sort of a stack that holds the forms being opened, but that kind of defeats the purpose behind calling a call chain handler in the first place.

I guess I should have asked; is there something I can do? Or am I stuck without the knowledge of the originating table?

I agree it would be a useful addition. But hopefully you could just use the Current form table command in your error logging.

Look carefully at the attached picture. As you can see, by the time I am aware that I am going to need a table name, that table name is no longer available.

The particularly frustrating bit is that their call chain can see it, while mine cannot. I find that to be a very surprising shortcoming.

If you are stacking forms, you could still accomplish the logging you need by keeping track yourself when the form is loaded/unloaded.

I think Get Call Chain command should have included the method path on each call to address your issue.

Hi Chris,

In your screenshot you have a pointer to retrieve Get call chain result. The command returns a collection so a pointer is not required

Then obviously there is something more to this, because sending the object directly as a parameter does not work.



Looks like I lost the fourth picture…


What happens if you define a_callChain as collection before call the method “setCallChain”?

a_callChain:=new collection
setCallChain (a_callChain)


“a_CallChain” (for the address form), and “p_CallChain” (for the person form) is defined in the ON LOAD event of the main input forms. That doesn’t work, I can’t imagine that moving it to inside the button event handler would improve things.

But I want to call a halt to this whole line of discussion before it goes too far off the rails. In our real code we start by setting a “logging” error trap function early in the startup. We call a function from inside there that assembles what we want to know about the particular error. That call-set uses pointers because we set different error trapping functions in certain places that might e.g. pop an alert to the user instead of (or sometimes in addition to) writing to a table. In the assembly code we have no way of knowing where the data will wind up, so we use pointers to make it nicely generic.

Assuming we are logging the error to a row in a table (like we would be in this case), then the function that now gets the call chain sets the value into a field that it gets via a pointer. If we were to e.g. set the value directly into a variable (like I did in my SSCCE), then the value would show up interactively without changes. In our real code, that pointer would likely point to a field in a table row. The salient point being that the code that assembles the error message doesn’t know that.

Yes I could set $0:=Get call chain - but then that defeats the purpose of having a generic function that handles all types of error traps. Right now we have one function that assembles all the data, and all code filters through that. I added one line of code to my error logging function, I added one field to my table, and suddenly all the places that pass through that error trap can have knowledge of the call chain if it wants it.

General suggestions to all that post:
Any time you are looking at code that is blazingly obviously a minimal example whose only purpose is to expose some aspect of the code - then suggestions of this nature serve only to distract from the real purpose of the post. It’s safe to say that now that we have gone this far off the rails, nobody will bother to look at the central point of the original post, which is to say that “Get call chain” does not capture the table from table forms.


I build this demo very quickly. Is it that screen you expect to get?
Capture d’écran 2020-05-22 à 16.38.48

Look at the very first picture. In that picture, you can see that my debug trace starts at [Address].Input. From there I click the “Edit” button, which opens the [Person].Input form. I have on that form a button which calls “SetCallChain” which simulates my error trap function. That would be an actual error trapping function in my real code, not something that one calls manually.

As you can clearly see, any knowledge of the original table [Address] is unavailable inside my simulated error trap. This closely approximates what we have in the field, where we have forms that open dialogs, that open other dialogs, that call code, that call still other dialogs.

Yes it’s a crappy design by modern standards. What can I say, the application had its start probably 20 years ago - there are more than 5000 forms, and we’re probably over a million LOC at this point - we were nearly there ~5 years ago when I wrote a script to count LOC. This is being maintained by 3 people that service roughly 1000 users, so saying “just redesign the application” is not an option.

My point being that in the precise example I show above, I would like to have some way to capture [Address] in the call chain. As I’ve already said, it’s frustrating that the debugger’s call chain can see that information, but the function call cannot.

I’m not particularly excited about modifying every form so that it pops it’s table name onto a stack at load off again at unload, if I had time to do that I would instead invest that time in redesigning the interface.

Here is that in the form of a picture. Look at the simulated values, which I created by filling arrays by hand. Simulated shows my goal, real shows what I get. And as I say, I don’t really have the option of modifying all forms to push that value into a stack as I go.

Sorry my comment belongs not directly/realy to this theme form/subform/tableForm.
Just a try/begin to build a callChain History like process call ->next process…
a call chain beginning from root and and over the processes.
Yes, a new process called from another is no sub-process,
but i want to see from where something is started from the root over the processes.
Example, have a company-IN-form with a button “Add new persons” which started new process
and opens person-OUT-Form to add new persons to company,
again in the person-Form have another button “Add countries”
which opens again new countries-OUT-Form …same game…so on
…working with independent levels/tasks
But a historie over processses needed,
because some bugs/problems exist only in very specific call orders
which must be written in a protocol.
So it is helpfully to have a complete callChain Historie over the processes.
Maybe it helps to see how did i combine the callChains to get a historie.

Using 4D 18, it would be trivial to write some code that inserts a project method or two into every form method. If you don’t already have a project method that handles common events across forms, I have always found that to be very useful.

You might consider posting this issue as a feature request. I doubt 4D will take any action on it based on the discussion here.

Using 4D 18, it would be trivial to write some code that inserts a project method or two into every form method. If you don’t already have a project method that handles common events across forms, I have always found that to be very useful.

Trivial to write perhaps, not necessarily so trivial to make sure we don’t blow up some obscure form. But point taken.

I like the idea of a feature request, since it seems like 4D’s only change would be to augment something they already do. I’ve never done a feature request before - where would I find that?

I think this is not a feature request it is a bug,
when in callChain the table-name is missing.
To identify a table-form and a table-form-object-method
you need always the table name!
In my own changeLog i write always the name,
because forms with name “IN” we had with same name in 300 Tables.
// [person];“IN”.myButton // LastChange myName myDate
Every where 4D respect this and add a table-name in front of the form-name
when it is a table-form and not a project-form.
I think 4D only forget this in call-chain to do and test only with project forms.

I think that this came about because 4D is so focused on the idea that “modern” interfaces should not chain form calls like that. That’s something I’ll keep in mind when I arrive in Utopia where all my code is brand-new. Here on Earth I have to deal with code that was written so long ago that some of the developers have died of old age. Internally we often joke that our code base is like archaeology. Simply put, I do not have the ability to turn on a dime like that just because 4D thinks I should.

I agree that this is a bug, but regardless - it’s something that at least should change. So bug report, feature request, smoke signals, whatever. I’d just like to bring this to the attention of someone that might make a change.

If you click on “Forms List” at the top of the page, you should see a “Feature Request” forum on the left side of the page.

Posting a bug report is a lot more complicated. I think you have to open a case with 4D Tech Support.

I have to admit, “Feature Request” was right there staring me in the face and I’ve never seen it. Thanks! :grinning:

Feature requested here: The request