D-tails 1: local this

This is the first in an on-going series of posts relating nuggets of D wisdom gained through daily praxis.

this is a local variable”

I recently came across the situation where I needed to pass a pointer to an object to a callback function in a C library. The function was designed so that you can pass ‘additional data’ by means of a void*, which could be used to point to any kind of data in memory which would contain the context for the callback. This is a fairly common pattern in C libraries, designed to make the callbacks flexible and extensible to any use case.

Here’s a simplified example of the situation:

[d]
class MyClass
{
// Method to register a request with the C library, passing a reference
// to this object as the ‘context’, which will be passed to the C callback
// function below when the request is processed.
void register ( )
{
void* pointer_to_this /* = ? */;
CLibraryFunction(pointer_to_this);
}

// Callback
extern ( C ) static private void callback ( void* context )
{
// somehow cast the ‘context’ argument to an object reference
// and do something with it
}
}
[/d]

So the question is, how to get the address of an object, from inside it, to pass to the C library function? And how to convert it back to a usable object reference inside the callback function?

My initial instinct was:

[d]
void* pointer_to_this = &this;
[/d]

Sounds fair enough, right? But unfortunately it’s not that simple. After some research I turned up the fairly obscure fact that this is actually a local variable which is implicitly added to the every method’s parameter list. This means that by taking the address of this, all we get is a pointer to somewhere in the stack, which is not at all what was intended!

The solution is to think about what this actually is: a reference to an object. So we can cast the reference directly to a void*, and then cast it directly back – there’s no need to take the address of it or to dereference it at the other end using the * operator.

[d]
class MyClass
{
// Method to register a request with the C library, passing a reference
// to this object as the ‘context’, which will be passed to the C callback
// function below when the request is processed.
void register ( )
{
void* pointer_to_this = cast(void*)this;
CLibraryFunction(pointer_to_this);
}

// Callback
extern ( C ) static private void callback ( void* context )
{
MyClass object = cast(MyClass)context;
// do something with object
}
}
[/d]

More D language “D-tails” to come.

Are you smart? Innovative? Driven? If you’re interested in working on challenging projects in one of the world’s most fast-paced industries, why not check out the openings on our Careers page?

Back to news overview