Jump to page: 1 2
Thread overview
Problems with function as parameter
Sep 21, 2017
Josh
Sep 21, 2017
Matt Jones
Sep 22, 2017
Mike Parker
Sep 22, 2017
Mike Parker
Sep 22, 2017
Josh
Sep 22, 2017
Mike Parker
Sep 22, 2017
Mike Parker
Sep 22, 2017
Josh
Sep 22, 2017
Mike Parker
Sep 22, 2017
Josh
Sep 22, 2017
user1234
September 21, 2017
I'm trying to write a callback function for SDL_mixer through Derelict, but this is the first time I've tried to use a function as a parameter, and so I think I'm just making a minor mistake somewhere.

The C SDL docs say:
****************************************************
// make a channelDone function
void channelDone(int channel)
{
    printf("channel %d finished playing.\n", channel);
}
...
// set the callback for when a channel stops playing
Mix_ChannelFinished(channelDone);
****************************************************

And my D code is:
****************************************************
void unmuteAfterPlaySound()
{
	Mix_ChannelFinished(channelDone);
}

void channelDone(int channel)
{
	unmuteMusic();
}
****************************************************

But DMD seems to be trying to run channelDone() i.e. with no parameters and parentheses omitted, and is giving this error:

Error: function Mixer.channelDone (int channel) is not callable using argument types ()
Error: function pointer Mix_ChannelFinished (extern (C) void function(int channel)) is not callable using argument types (_error_)

Is anyone able to see what I've done wrong? Any help would be appreciated, thanks.
September 21, 2017
On Thursday, 21 September 2017 at 20:21:58 UTC, Josh wrote:
> I'm trying to write a callback function for SDL_mixer through Derelict, but this is the first time I've tried to use a function as a parameter, and so I think I'm just making a minor mistake somewhere.
>
> [...]

Make it a C function, not a D function:

extern (C) void channelDone(int channel)
{
	unmuteMusic();
}

and use & to reference the function instead of calling it:

Mix_ChannelFinished(&channelDone);
September 22, 2017
On Thursday, 21 September 2017 at 22:05:22 UTC, Matt Jones wrote:
> On Thursday, 21 September 2017 at 20:21:58 UTC, Josh wrote:
>> I'm trying to write a callback function for SDL_mixer through Derelict, but this is the first time I've tried to use a function as a parameter, and so I think I'm just making a minor mistake somewhere.
>>
>> [...]
>
> Make it a C function, not a D function:
>
> extern (C) void channelDone(int channel)
> {
> 	unmuteMusic();
> }
>
> and use & to reference the function instead of calling it:
>
> Mix_ChannelFinished(&channelDone);

It should be extern(C) and, ideally, nothrow. The binding should be enforcing nothrow, but currently doesn't. I'll change that now.
September 22, 2017
On Friday, 22 September 2017 at 02:18:34 UTC, Mike Parker wrote:

>>
>> and use & to reference the function instead of calling it:
>>
>> Mix_ChannelFinished(&channelDone);

To expand on this, D allows functions to be called without parentheses. `channelDone` is actually a function call, whereas in C, it's treated as a function pointer. In D, you have to take the address of a function just as you would any other type, hence `&channelDone`.

September 22, 2017
On Thursday, 21 September 2017 at 22:05:22 UTC, Matt Jones wrote:
> On Thursday, 21 September 2017 at 20:21:58 UTC, Josh wrote:
>> I'm trying to write a callback function for SDL_mixer through Derelict, but this is the first time I've tried to use a function as a parameter, and so I think I'm just making a minor mistake somewhere.
>>
>> [...]
>
> Make it a C function, not a D function:
>
> extern (C) void channelDone(int channel)
> {
> 	unmuteMusic();
> }
>
> and use & to reference the function instead of calling it:
>
> Mix_ChannelFinished(&channelDone);

Thanks for the help, but when I try that, I get:

src\mixer.d(80,22): Error: function pointer Mix_ChannelFinished (extern (C) void function(int channel)) is not callable using argument types (extern (C) void delegate(int channel))

Code:
void unmuteAfterPlaySound()
{
	Mix_ChannelFinished(&channelDone);
}

extern (C) void channelDone(int channel)
{
	unmuteMusic();
}
September 22, 2017
On Friday, 22 September 2017 at 02:18:34 UTC, Mike Parker wrote:
> On Thursday, 21 September 2017 at 22:05:22 UTC, Matt Jones wrote:
>> On Thursday, 21 September 2017 at 20:21:58 UTC, Josh wrote:
>>> I'm trying to write a callback function for SDL_mixer through Derelict, but this is the first time I've tried to use a function as a parameter, and so I think I'm just making a minor mistake somewhere.
>>>
>>> [...]
>>
>> Make it a C function, not a D function:
>>
>> extern (C) void channelDone(int channel)
>> {
>> 	unmuteMusic();
>> }
>>
>> and use & to reference the function instead of calling it:
>>
>> Mix_ChannelFinished(&channelDone);
>
> It should be extern(C) and, ideally, nothrow. The binding should be enforcing nothrow, but currently doesn't. I'll change that now.

Why should the binding force nothrow? I don't understand why you HAVE to not throw exceptions. Is it because of the C -> D aspect?
September 22, 2017
On Friday, 22 September 2017 at 02:22:46 UTC, Josh wrote:

>
> src\mixer.d(80,22): Error: function pointer Mix_ChannelFinished (extern (C) void function(int channel)) is not callable using argument types (extern (C) void delegate(int channel))
>
> Code:
> void unmuteAfterPlaySound()
> {
> 	Mix_ChannelFinished(&channelDone);
> }
>
> extern (C) void channelDone(int channel)
> {
> 	unmuteMusic();
> }

The error message indicates that `channelDone` is a member of a class or a struct. A pointer to a member function is a delegate (or closure), not a function pointer. Free functions, static nested functions, and static member functions all produce function pointer. Non-static member functions and non-static nested functions all produce delegates/closures. See the docs:

https://dlang.org/spec/function.html#closures

If you need to manipulate instance members from a C callback, you'll need a way to implement a mechanism to work out which instance you need.

September 22, 2017
On Friday, 22 September 2017 at 02:32:56 UTC, Josh wrote:

> Why should the binding force nothrow? I don't understand why you HAVE to not throw exceptions. Is it because of the C -> D aspect?

Yes, it's because D exceptions are not guaranteed to propagate through the C callstack. It works on some compiler/platforms, but not others. I wrote an article at Gamedev.net (which apparently no longer picks up the site's stylesheets) which shows one way of dealing with it. I've modified my approach since then (and should write a better article about it), but the basic idea still holds.
September 22, 2017
On Friday, 22 September 2017 at 02:32:56 UTC, Josh wrote:

> Why should the binding force nothrow? I don't understand why you HAVE to not throw exceptions. Is it because of the C -> D aspect?

Yes, it's because D exceptions are not guaranteed to propagate through the C callstack. It works on some compiler/platforms, but not others. I wrote an article at Gamedev.net (which apparently no longer picks up the site's stylesheets) which shows one way of dealing with it. I've modified my approach since then (and should write a better article about it), but the basic idea still holds.

https://www.gamedev.net/articles/programming/general-and-gameplay-programming/d-exceptions-and-c-callbacks-r3323/
September 22, 2017
On Friday, 22 September 2017 at 03:26:36 UTC, Mike Parker wrote:
> On Friday, 22 September 2017 at 02:22:46 UTC, Josh wrote:
>
>>
>> src\mixer.d(80,22): Error: function pointer Mix_ChannelFinished (extern (C) void function(int channel)) is not callable using argument types (extern (C) void delegate(int channel))
>>
>> Code:
>> void unmuteAfterPlaySound()
>> {
>> 	Mix_ChannelFinished(&channelDone);
>> }
>>
>> extern (C) void channelDone(int channel)
>> {
>> 	unmuteMusic();
>> }
>
> The error message indicates that `channelDone` is a member of a class or a struct. A pointer to a member function is a delegate (or closure), not a function pointer. Free functions, static nested functions, and static member functions all produce function pointer. Non-static member functions and non-static nested functions all produce delegates/closures. See the docs:
>
> https://dlang.org/spec/function.html#closures
>
> If you need to manipulate instance members from a C callback, you'll need a way to implement a mechanism to work out which instance you need.

Perfect, that's the info I needed. As these functions were in a class, setting channelDone and unmuteMusic to static worked.

As an aside, in that doc it says "The .funcptr property of a delegate will return the function pointer value as a function type". So I also tried Mix_ChannelFinished((&channelDone).funcptr); and this compiled, but caused a segfault when
the callback ran. What would have caused this? Is it because it's a C function?
« First   ‹ Prev
1 2