December 14, 2004
Tyro wrote:
> 
> Actually I just came home and didn't get a chance to read your responses as yet. I just did a quick scan to see who had responded to my post and gave thanks where it was due.

Oh, okay.  :-)

> I am a purist, so I believe that D programs should be written in D. Maybe at the onset (just to get some functionality that is not yet available in the language) we can wrap up C functions for use in our programs until the "D-way" is devised. Then those functions should be reimplemented in accordance with the way things are done in D.

He, he.  Well, I'd love to be a purist too, but I'm not yet up to the task of reimplementing the whole windows API, Linux API, OpenGL, SDL, etc.  As long as those are around, we'll need some extern(C)'s to get things going at the lowest levels.  A new OS would be nice, though, with strictly D calling convention! Now wouldn't that be Utopia! :-D

> To this end I was simply wondering how C function pointers differ from D function pointers (as you stated above) and the proper way to "D"-up a function pointer or delegate to accomplish the same thing the C function pointer would.

Righto.  I'm sure there's room for more discussion on this still.  The function and delegate keywords are really fun tools in the D arsenal.

Glad to help,

John
December 15, 2004
Does your examples cover say OpenGL extensions which must be acquired through wgl (Windows API for OpenGL) then casted to a function pointer?

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/opengl/ntopnglr_6yer.asp

I have run into this issue also with glfw, which is a library which
hides the Windows specifics API.  It allows you to register callback functions which need C calling conventions.

New libraries should be done 'right' in D, but the lure of C is its access to low-level hardware and OS features.

My $.02
-Ash

<snip>
> I am a purist, so I believe that D programs should be written in D. Maybe at the onset (just to get some functionality that is not yet available in the language) we can wrap up C functions for use in our programs until the "D-way" is devised. Then those functions should be reimplemented in accordance with the way things are done in D.
> 
> To this end I was simply wondering how C function pointers differ from D function pointers (as you stated above) and the proper way to "D"-up a function pointer or delegate to accomplish the same thing the C function pointer would.
> 
> Cheers,
> Andrew
December 15, 2004
David Medlock wrote:
> Does your examples cover say OpenGL extensions which must be acquired through wgl (Windows API for OpenGL) then casted to a function pointer?
> 
> http://msdn.microsoft.com/library/default.asp?url=/library/en-us/opengl/ntopnglr_6yer.asp 

I took a quick look at the link, and I think that there should be no problem whatsoever.  You should be able to do something like this:



NOTE: I haven't done careful analysis to make sure that LPCSTR is really a 'char*', so this is just a rough sketch:



extern(C) void *wglGetProcAddress(char*);
extern(C) int function() glFunctionIWantToUse =
	cast(extern(C) int function())
		wglGetProcAddress("glFunctionIWantToUse");



This discussion has resulted in us discovering a couple of bugs with how dmd handles extern(C) function pointers, so I suspect that the compiler will (right now) choke on the cast above.  But I think that this should work, once the bugs are cleared up.  (I hope that I'm right, and that Walter consideres them bugs.)

December 15, 2004
Tyro wrote:
> Actually I just came home and didn't get a chance to read your responses as yet. I just did a quick scan to see who had responded to my post and gave thanks where it was due.
> 
> I am a purist, so I believe that D programs should be written in D. Maybe at the onset (just to get some functionality that is not yet available in the language) we can wrap up C functions for use in our programs until the "D-way" is devised. Then those functions should be reimplemented in accordance with the way things are done in D.
> 
> To this end I was simply wondering how C function pointers differ from D function pointers (as you stated above) and the proper way to "D"-up a function pointer or delegate to accomplish the same thing the C function pointer would.

Well, I'm not sure from what you wrote whether you already know all that you want to know.  So, since I like to expound on these things, and since (maybe) you want to know more, here's a more technical explanation:

The first thing to remember is that C function pointers are simply pointers to some address in memory.  They contain, in their type data, information about the arguments and the return type, but at runtime, they are just a pointer like any other pointer.  You can cast a function pointer to a void* and then get the address of the function in memory, for example.  Likewise, you can cast a void* back to a function pointer.

D function pointers are the same thing.  They are a simple, single pointer.

When you call a function pointer in either language, the code puts your arguments (if any) onto the stack, and then makes a subroutine call to whatever address is stored in the function pointer.

The only difference between D and C function pointers is that (in some architectures) the calling convention may be different.  There are various assumptions made by each language (who saves copies of registers, who cleans up the stack, the order of arguments on the stack, etc.) which may vary from language to language.  The point of
	extern(C)
is to inform the D compiler that it is talking to a C function, and so it must talk like a C function.  This may be different than D's conventions.

This is why you can't store a pointer to a D function in an extern(C) function pointer, or vice-versa.  If the function pointer is declared extern(C), then you are saying that the compiler should use C calling conventions when it calls the function.  If it is actually a D function, then things will break.  To solve this, you implement a trivial wrapper function, which calls the function pointer.  It serves as an interpreter between the D function and the C function.  You can use wrappers in either direction; to store a pointer to a C function in a D function pointer, then create a D wrapper which calls the C function; the opposite also works.

Delegates are another beast.  They are a bit of a conceptual jump, but once you get used to them you'll never want to go back.  Delegates are actually two pointers stored in a single variable.  One of the pointers is a function pointer to a D function; the other is a void*.  When you call a delegate, it passes the void* as the implicit first argument. This is exactly like how class member functions are called.

Think about how a class member function works.  Look at this example:

class Foo {
  int val;
  int foo() { return val; }
}
int bar(Foo f) { return f.val; }

The functions Foo.foo() and bar(Foo) are pretty much the same function.  The class member function has an implicit argument (Foo) which is automatically passed when you call the member.  So the code below, which calls the two functions, is almost identical when you get down to the bare metal:

Foo f = new Foo;
...
int x = f.foo();
int y = bar(f);

Delegates work the same way.  They just carry around the "this" pointer hidden inside the delegate.  So this delegate:

int delegate() dg = *f.foo;

is pretty much the same thing as this struct:

struct my_delegate {
  int function(void*) func;
  void *ptr;
};
my_delegate my_dg;
my_dg.func = cast(int function(void*))&bar;
my_dg.ptr  = cast(void*)f;

And calling the delegate:

int a = dg();

is just like calling the function pointer with the stored argument:

int b = my_dg.func(my_dg.ptr);



I would highly recommend that, in your D programs, you always use a delegate any time that you might think about using a function pointer. They are far more flexible; if you ever, in the future, decide that you needed a delegate, they are there.  You can always write a wrapper function which turns a function into a delegate:

int myFunc();
int delegate() dg = &myFunc();
	/* syntax error, can't save funcptr in a delegate */
int delegate() dg = delegate int() { return myFunc(); }
	/* ok! */

(Technically, you've created a stack delegate above.  The 'ptr' of the delegate is actually a pointer to the current stack frame...but since we don't ever use any stack variables, we don't care about the fact that the stack frame isn't valid later on.)



The only complexity here is that if you have a function pointer variable and you have to turn it into a delegate.  Then you have to write a tiny struct, and take a delegate from a member function of that struct:

int delegate() ConvertFuncPtrToDelegate(int function() func) {
  struct Storer {
    int function() func;
    int Call() { return func(); }
  };
  Storer *temp = new Storer[1];
  temp.func = func;
  return &temp.Call();
}



Hope all this helps.

December 15, 2004
Russ Lewis wrote:
> David Medlock wrote:
> 
>> Does your examples cover say OpenGL extensions which must be acquired through wgl (Windows API for OpenGL) then casted to a function pointer?
>>
>> http://msdn.microsoft.com/library/default.asp?url=/library/en-us/opengl/ntopnglr_6yer.asp 
> 
> 
> 
> I took a quick look at the link, and I think that there should be no problem whatsoever.  You should be able to do something like this:
> 
> 
> 
> NOTE: I haven't done careful analysis to make sure that LPCSTR is really a 'char*', so this is just a rough sketch:
> 
> 
> 
> extern(C) void *wglGetProcAddress(char*);
> extern(C) int function() glFunctionIWantToUse =
>     cast(extern(C) int function())
>         wglGetProcAddress("glFunctionIWantToUse");
> 

It's very likely that these would have to be declared extern(Windows) to account for the WINAPI calling convention.  But your example gives the general idea.  The Derelict project does this already... So does Kris' Mango.icu.  People can browse both of these projects over at www.dsource.org to see how it's done in a real world situation.  Both access Win32 LoadLibrary() and GetProcAddress() calls to fill function pointers similar to the way you've done it above.  Mango.icu uses a little more structured approach to do the same thing: primarily it casts the function pointers to void* type before assigning the result from GetProcAddress().

> 
> This discussion has resulted in us discovering a couple of bugs with how dmd handles extern(C) function pointers, so I suspect that the compiler will (right now) choke on the cast above.  But I think that this should work, once the bugs are cleared up.  (I hope that I'm right, and that Walter consideres them bugs.)
> 

I'm not so sure that they are bugs, per se.  They do appear to be severe short-comings.  I believe the compiler has just severely limited where and when extern(...) can be used.  I readily admit that it would be /really/ nice to use the extern(...) decoration in places like function literals, nested functions, non-static class members, and so on; but I'm not sure how technically feasible it is.  Like you, I hope Walter can fix it or clarify the extent of the problem.

Later,

John
December 15, 2004
Russ Lewis wrote:
> Tyro wrote:
> 
>> Actually I just came home and didn't get a chance to read your responses as yet. I just did a quick scan to see who had responded to my post and gave thanks where it was due.
>>
>> I am a purist, so I believe that D programs should be written in D. Maybe at the onset (just to get some functionality that is not yet available in the language) we can wrap up C functions for use in our programs until the "D-way" is devised. Then those functions should be reimplemented in accordance with the way things are done in D.
>>
>> To this end I was simply wondering how C function pointers differ from D function pointers (as you stated above) and the proper way to "D"-up a function pointer or delegate to accomplish the same thing the C function pointer would.
> 
> 

[ some great information ]

> 
> Hope all this helps.
> 

Immensely! Russ, your coverage of the topic was exceptional and greatly appreciated. My question is now answered.

Seems to me though that the mere existence of delegates obviates the need for function pointers in D. I would say that a merger of the two is warranted.

Andrew
December 15, 2004
Tyro wrote:
> Russ Lewis wrote:
>>
>> Hope all this helps.
>>
> 
> Immensely! Russ, your coverage of the topic was exceptional and greatly appreciated. My question is now answered.
> 
> Seems to me though that the mere existence of delegates obviates the need for function pointers in D. I would say that a merger of the two is warranted.
> 
> Andrew

Or perhaps use *function* as pointers to C functions, and delegates always have D linkage?
Delegates have a pointer + a stack frame, so if the stack frame is 0, then its a pointer to a regular function? Just a thought.

Walter, we really need a way to call passed C function pointers even if it is through a pragma or other compiler-specific way.
December 15, 2004
Tyro wrote:
> Seems to me though that the mere existence of delegates obviates the need for function pointers in D. I would say that a merger of the two is warranted.

For most applications, I would agree.  But, since one of the goals of D "systems programming" (kernel design), I'm not sure that we want to get rid of function pointers altogether.  It's nice to have a smaller, more efficient type.

December 15, 2004
Russ Lewis wrote:

> Hope all this helps.

I must admit, that was a very good description!

- John
1 2
Next ›   Last »