Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get the calling object or method in d

Tags:

d

Somewhat related to my previous question here

Is there a way to get the calling Object from within a function or method in d?

example:

class Foo
{
    public void bar()
    {
        auto ci = whoCalledMe();
        // ci should be something that points me to baz.qux, _if_ baz.qux made the call

    }
}

class Baz
{
    void qux()
    {
        auto foo = new Foo();
        foo.bar();
    }
}

Questions:

  1. Does something like whoCalledMe exist? and if so, what is it called?
  2. if something does exist, can it be used at compile time (in a template) and if so, how?

Alternatively;

  1. is it possible to get access to the call stack at runtime? like with php's debug_backtrace?
like image 413
Kris Avatar asked Aug 13 '13 13:08

Kris


3 Answers

To expand on what CyberShadow said, since you can get the fully qualified name of the function by using __FUNCTION__, you can also get the function as a symbol using a mixin:

import std.stdio;
import std.typetuple;

void callee(string file=__FILE__, int line=__LINE__, string func=__FUNCTION__)()
{
    alias callerFunc = TypeTuple!(mixin(func))[0];
    static assert(&caller == &callerFunc);

    callerFunc();  // will eventually overflow the stack
}

void caller()
{
    callee();
}

void main()
{
    caller();
}

The stack will overflow here since these two functions end up calling each other recursively indefinitely.

like image 155
Andrej Mitrović Avatar answered Sep 22 '22 17:09

Andrej Mitrović


It's not directly possible to get information about your "caller". You might have some luck getting the address from the call stack, but this is a low-level operation and depends on things such as whether your program was compiled with stack frames. After you have the address, you could in theory convert it to a function name and line number, provided debugging symbols are available for your program's binary, but (again) this is highly platform-specific and depends on the toolchain used to compile your program.

As an alternative, you might find this helpful:

void callee(string file=__FILE__, int line=__LINE__, string func=__FUNCTION__)()
{
    writefln("I was called by %s, which is in %s at line %d!", func, file, line);
}

void caller()
{
    // Thanks to IFTI, we can call the function as usual.
    callee();
}

But note that you can't use this trick for non-final class methods, because every call to the function will generate a new template instance (and the compiler needs to know the address of all virtual methods of a class beforehand).

like image 42
Vladimir Panteleev Avatar answered Sep 25 '22 17:09

Vladimir Panteleev


Finding the caller is something debuggers do and generally requires having built the program with symbolic debug information switches turned on. Reading the debug info to figure this out is highly system dependent and is pretty advanced.

The exception unwinding mechanism also finds the caller, but those tables are not generated for functions that don't need them, and the tables do not include the name of the function.

like image 30
Walter Bright Avatar answered Sep 23 '22 17:09

Walter Bright