How know Who Is calling sub or function

Is It possibile (from inside the sub or function called ) retrieve the name of object.method or other sub or function that Is calling a sub or function ?

Example :
I have subA , subB, cmdButtonC

Inside subB i call subA
Insider cmdButtonC.click i call subA

From inside the code of subA i would like read if subA Is called by subB or by cmdButtonC.click event

Yes. Just raise and catch an exception. The calling method will be the second item in the stack.

2 Likes

Have a look at ExceptionHandler from Xojo + Alfred .

2 Likes

While it is possible to inspect the stack and thus the calling chain, an arguably cleaner approach would be to pass everything the called method needs in a parameter. In whichever way the identity of the caller might be relevant there is a way to capture that information in an additional parameter. Chances are this would also be more efficient.

6 Likes

Omg, that would be a pain to manage. You’d have to remember to do that for every method and remove the items when you returned from the methods. The stack does that for you.

2 Likes

Depends on what you are doing. When a method must do different things depending on the who is the caller, this usually means that some information is needed that caller could have provided but didn’t. In that case it is much cleaner if it simply did provide this missing info.

Now of course there are situations when you really need to know the caller, like when you are compiling a statistics about which method is calling which other method, but these situation should be rare I think.

1 Like

Take a closer look at the stack, as @Greg_O already recommended. This is probably the easiest method. :slight_smile:

#Pragma BreakOnExceptions False
Try
  
  Var WhoIsCallingMe As New RuntimeException("Information about the caller", 999)
  Raise WhoIsCallingMe
  
Catch e As RuntimeException
  
  Var stack() As String = e.Stack()
  MessageBox stack(1)
  
End Try
#Pragma BreakOnExceptions True

“MessageBox stack(0)” replaced with “MessageBox stack(1)”
Updated after Gregs Note regarding current Method. Thank you Greg :slight_smile:

Messagebox stack(1)

0 would be the current method.

3 Likes

I’m not following what this is or how it’s a problem. Michael wasn’t suggesting building a copy of the stack.

subA(true) to indicate it came from a user action like button click and subA(false) to indicate it came from within code like subB is much simpler and cleaner.

As I recall, isn’t catching and raising exceptions a performance hit?

1 Like

Ok but if i must pass a parameter .. the delineated solution Is not usefully

You know it is, but sometimes…

This is what I do when I need to figure it out - I just add optional callerID as String to the parameter of the method and use System.DebugLog(“Called from :” + callerID) to add it to the log.
I add the CurrentMethodName to the whatever’s calling the method.

It’s a bit of work, but it won’t slow things down, and you can view the log as it happens.

5 Likes

Its a very usual design, specially for event like calls, passing the “sender”. Usually a class that fired such event (i.e. called the method) so you just know the origin, and even access it, but depending on the design could be any path tracking, as a enum for example.

In the OP case it could be as simple as

Public Enum CallOrigin
  ButtonPressed
  DirectCall
End Enum

Public Sub FinalMethod(origin As CallOrigin = CallOrigin.DirectCall)
  If origin = CallOrigin.ButtonPressed Then
    // was the button
  Else
    // Direct Call
  End
End Sub

In every method or event handler of my larger apps I have a line of code like:

if globalVariableTraceMyCode then LogTransaction CurrentMethodName + " "+ myParams

globalVariableTraceMyCode is set to true while debugging. You can remove this stuff later once it’s all sorted.

LogTransaction is a logging module that provides a sequential event number and timestamp, writes to a text file and flushes that to disk, so it’s there even if the app crashes. Quite helpful if you need to work out exactly what happened in what order.

1 Like

ok but the most interesting question would be who calls a sub or a function, the method is mostly called by the object to which it belongs..
now, it seems heavy to me to have to call a function that logs what I’m doing to which to pass both the object that calls it and the method that calls it, doing so I have not automated anything and it is useless to talk about object-oriented programming paradigms if I cannot intercept via code who calls what …

the code to generate the logs must be minimal and not full of parameters to pass to it, otherwise it is a nuisance

But that’s what the Stack is made for…?

Again, the following should solve your problem:

Public Sub WhoIsCallingMe()
  #Pragma BreakOnExceptions False
  Try
    
    Var WhoIsCallingMe As New RuntimeException("Information about the caller", 999)
    Raise WhoIsCallingMe
    
  Catch e As RuntimeException
    
    Var stack() As String = e.Stack()
    System.DebugLog stack(1).Replace("%%", " in ")
    
  End Try
  #Pragma BreakOnExceptions True
End Sub

Add the above to a Module and call it from where ever you need to know who’s calling :wink:

The DebugLog will show something like this:

10:12:59 : My Application.exe Launched
10:13:00 : Window1.Window1.Event_Opening in o<Window1.Window1>
: Window1.Window1.Untitled in o<Window1.Window1>
: Module1.Test_A
10:13:04 : My Application.exe Ended

4 Likes

As much as I think needing to know the caller means the design is suboptimal, I’d agree with Greg and Sascha that one should use the built in stack rather than tracking their own.

3 Likes

great, apart from noting that in your ways I assume you studied at Oxford,
if we reasoned like you we would also have to throw away the whole part of opportunity to manage introspection.

Ps. what I don’t like about generating an error and querying the stack to understand who the caller is is precisely the issue of generating an error, which I don’t think is the best for the speed of execution of the code.

This is exactly why it was suggested to pass the required information in through method parameters:

Heck, if I were stuck in this position, I might even use different public methods with a shared central core.

2 Likes

That’s true if this information were needed every time a method is called.
If that’s actually the case, then I would, like @Tim_Parnell, suspect that your solution is suboptimal. There must be another, better way. But until we learn more about why your solution should look the way you want it to, we can only help suboptimally. :slight_smile:

3 Likes