www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - callback craziness

reply Engine Machine <EM EM.com> writes:
I use callbacks a lot and have trouble with D in a nogc context.

First, I cannot declare the parameters with a nogc or I get a 
compile time error.

 nogc void foo(void delegate(int x)  nogc f);

fails with the  nogc.

2nd, I cannot use a delegate because of the  nogc context,

 nogc void foo(void function(int x) f);

Works, but f then cannot access the context.

So, to get around these problems, I have to do something like 
this:

alias callback(Args) =  nogc void function(int x, Args);
 nogc void foo(Args...)(callback!Args f, auto ref Args args, int 
extra = 0)

The problem with this is that I can't seem to add f inline:

foo!string((int x, string s) { }, 1);

this fails with template mismatch.

But if I define the lambda outside it works:

auto f = (int x, string s) { };
foo!string(f, 1);

The problem with this is that when I want to pass no arguments,

auto f = (int x) { };
foo(f, 1);

fails. It seems that Args... requires at least one argument to 
match the template? This may be a bug?


alias callback(Args) =  nogc void function(string, int, Args);
 nogc public void foo(Args...)(callback!Args c, auto ref Args 
args, int extra = 0)
{
    ...
}
		
auto f = (string s, int l)  nogc
{
     printf("%s\n", s.ptr);
};
foo(f, 1);

or

auto f = (string s, int l, string x)  nogc
{
     printf("%s\n", x.ptr);
};
foo!string(f, "Test string", 1);

which is the case that work sin mine code. But I don't always 
want to have to pass stuff.

Any ideas? I realize the code is messy. You'll have to read 
between the lines.



So, the two problems I have is that I would like to be able to 
add a  nogc callback inline and to be able to pass no arguments.
Aug 07 2016
parent reply ag0aep6g <anonymous example.com> writes:
On 08/07/2016 10:01 PM, Engine Machine wrote:
  nogc void foo(void delegate(int x)  nogc f);

 fails with the  nogc.
Compiles just fine for me.
 2nd, I cannot use a delegate because of the  nogc context,
Delegates don't necessarily need a GC allocation. They only need it when they need a closure. Delegates of methods don't need closures. And when you pass the delegate in a `scope` parameter, no closure is needed, either. [...]
 So, to get around these problems, I have to do something like this:

 alias callback(Args) =  nogc void function(int x, Args);
  nogc void foo(Args...)(callback!Args f, auto ref Args args, int extra = 0)

 The problem with this is that I can't seem to add f inline:

 foo!string((int x, string s) { }, 1);

 this fails with template mismatch.
You're missing an argument there. The second parameter of foo is `args` which is `string` here. This call works: foo!string((int x, string s) { }, "", 1);
 But if I define the lambda outside it works:

 auto f = (int x, string s) { };
 foo!string(f, 1);
Doesn't work for me. Still missing the string argument.
 The problem with this is that when I want to pass no arguments,

 auto f = (int x) { };
 foo(f, 1);

 fails. It seems that Args... requires at least one argument to match the
 template? This may be a bug?
One thing you need to fix: The `callback` template needs a template sequence parameter (i.e. `Args...`). Otherwise it takes exactly one type. That doesn't make it work, though. You also need to add empty template instantiation parentheses (i.e. `foo!()`), and you need to remove `auto ref` from the `args` parameter. No idea why it doesn't work with `auto ref`. At least that part looks like a bug to me.
Aug 07 2016
parent reply Engine Machine <EM EM.com> writes:
On Sunday, 7 August 2016 at 20:48:29 UTC, ag0aep6g wrote:
 On 08/07/2016 10:01 PM, Engine Machine wrote:
  nogc void foo(void delegate(int x)  nogc f);

 fails with the  nogc.
Compiles just fine for me.
 2nd, I cannot use a delegate because of the  nogc context,
Delegates don't necessarily need a GC allocation. They only need it when they need a closure. Delegates of methods don't need closures. And when you pass the delegate in a `scope` parameter, no closure is needed, either.
Well, one can't pick the case the delegate is passed. When I use a delegate in the nogc context it errs.
 [...]
 So, to get around these problems, I have to do something like 
 this:

 alias callback(Args) =  nogc void function(int x, Args);
  nogc void foo(Args...)(callback!Args f, auto ref Args args, 
 int extra = 0)

 The problem with this is that I can't seem to add f inline:

 foo!string((int x, string s) { }, 1);

 this fails with template mismatch.
You're missing an argument there. The second parameter of foo is `args` which is `string` here. This call works: foo!string((int x, string s) { }, "", 1);
Yeah, that was just a typeo obvious. That's not the reason it fails.
 But if I define the lambda outside it works:

 auto f = (int x, string s) { };
 foo!string(f, 1);
Doesn't work for me. Still missing the string argument.
Yes, same typo.
 The problem with this is that when I want to pass no arguments,

 auto f = (int x) { };
 foo(f, 1);

 fails. It seems that Args... requires at least one argument to 
 match the
 template? This may be a bug?
One thing you need to fix: The `callback` template needs a template sequence parameter (i.e. `Args...`). Otherwise it takes exactly one type.
I did try that first and it didn't work. it works without ..., and I figured that it is a template parameter and can also represent a sequence? But I only tried with one argument so it worked. I added ... but same problems.
 That doesn't make it work, though. You also need to add empty 
 template instantiation parentheses (i.e. `foo!()`), and you 
 need to remove `auto ref` from the `args` parameter.

 No idea why it doesn't work with `auto ref`. At least that part 
 looks like a bug to me.
Yeah, so, this is typically what happens. One bug makes me change my tail for two hours ;/
Aug 07 2016
parent reply ag0aep6g <anonymous example.com> writes:
On 08/08/2016 12:08 AM, Engine Machine wrote:
 On Sunday, 7 August 2016 at 20:48:29 UTC, ag0aep6g wrote:
[...]
 Delegates don't necessarily need a GC allocation. They only need it
 when they need a closure. Delegates of methods don't need closures.
 And when you pass the delegate in a `scope` parameter, no closure is
 needed, either.
Well, one can't pick the case the delegate is passed. When I use a delegate in the nogc context it errs.
Not exactly. When you do something that requires a closure, it errors out. As I said, a delegate doesn't always require the allocation of a closure. This works just fine, and it uses a delegate parameter: ---- nogc void foo(void delegate(int x) nogc f) {} void main() nogc { foo((int x) {}); struct S { int y; void f(int x) nogc { this.y = x; } } S s; foo(&s.f); } ---- But this doesn't compile, because the delegate here would need a closure: ---- nogc void foo(void delegate(int x) nogc f) {} void main() nogc { int y; foo((int x) { y = x; }); } ---- Also note that it's main's nogc that makes this fail, not foo's or the parameter's. Remove main's nogc and it works. [...]
 You're missing an argument there. The second parameter of foo is
 `args` which is `string` here. This call works:

     foo!string((int x, string s) { }, "", 1);
Yeah, that was just a typeo obvious. That's not the reason it fails.
No. It's exactly the reason it fails. Add a string argument and it works: ---- alias callback(Args) = nogc void function(int x, Args); nogc void foo(Args...)(callback!Args f, auto ref Args args, int extra = 0) {} void main() nogc { foo!string((int x, string s) { }, "", 1); } ---- [...]
 One thing you need to fix: The `callback` template needs a template
 sequence parameter (i.e. `Args...`). Otherwise it takes exactly one type.
I did try that first and it didn't work. it works without ..., and I figured that it is a template parameter and can also represent a sequence?
No, without `...`, the template parameter only accepts exactly one type, not more than one, not none.
Aug 07 2016
next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Sunday, 7 August 2016 at 23:02:26 UTC, ag0aep6g wrote:
 Not exactly. When you do something that requires a closure, it 
 errors out. As I said, a delegate doesn't always require the 
 allocation of a closure.
You can also throw scope in there iff the delegate will never be stored: nogc void foo(scope void delegate(int x) nogc f) {} Then it won't allocate the closure even if it is a context that usually needs it, but if you store it then, you are liable to memory corruption.
Aug 07 2016
prev sibling parent reply Engine Machine <EM EM.com> writes:
On Sunday, 7 August 2016 at 23:02:26 UTC, ag0aep6g wrote:
 On 08/08/2016 12:08 AM, Engine Machine wrote:
 On Sunday, 7 August 2016 at 20:48:29 UTC, ag0aep6g wrote:
[...]
 Delegates don't necessarily need a GC allocation. They only 
 need it
 when they need a closure. Delegates of methods don't need 
 closures.
 And when you pass the delegate in a `scope` parameter, no 
 closure is
 needed, either.
Well, one can't pick the case the delegate is passed. When I use a delegate in the nogc context it errs.
Not exactly. When you do something that requires a closure, it errors out. As I said, a delegate doesn't always require the allocation of a closure. This works just fine, and it uses a delegate parameter: ---- nogc void foo(void delegate(int x) nogc f) {} void main() nogc { foo((int x) {}); struct S { int y; void f(int x) nogc { this.y = x; } } S s; foo(&s.f); } ---- But this doesn't compile, because the delegate here would need a closure: ---- nogc void foo(void delegate(int x) nogc f) {} void main() nogc { int y; foo((int x) { y = x; }); } ---- Also note that it's main's nogc that makes this fail, not foo's or the parameter's. Remove main's nogc and it works. [...]
 You're missing an argument there. The second parameter of foo 
 is
 `args` which is `string` here. This call works:

     foo!string((int x, string s) { }, "", 1);
Yeah, that was just a typeo obvious. That's not the reason it fails.
No. It's exactly the reason it fails. Add a string argument and it works: ---- alias callback(Args) = nogc void function(int x, Args); nogc void foo(Args...)(callback!Args f, auto ref Args args, int extra = 0) {} void main() nogc { foo!string((int x, string s) { }, "", 1); } ---- [...]
 One thing you need to fix: The `callback` template needs a 
 template
 sequence parameter (i.e. `Args...`). Otherwise it takes 
 exactly one type.
I did try that first and it didn't work. it works without ..., and I figured that it is a template parameter and can also represent a sequence?
No, without `...`, the template parameter only accepts exactly one type, not more than one, not none.
So, what about passing in the lambda verses the temp variable? I tried the ... same problem as I said. f!()(...) doesn't work. Everything works find as long as I pass more than one variable. My code is as follows and I cannot get 0 parameters working nor passing the function in directly. These were my original questions to begin with and haven't been answered. Here is the code I am using. alias callback(Args...) = nogc void function(string, int, Args); nogc public void foo(Args...)(callback!Args c, Args args, int x) { } foo((string s, int i) { }, 1); does not work nor does foo!()((string s, int i) { }, 1); Ultimately it would also be nice if the template parameters were deduced automatically instead of having to specify them. The compiler should be able to figure out the types supplied parameters. e.g., foo((string s, int i, T x) { }, someT, 1); instead of foo!(T)((string s, int i, T x) { }, someT, 1); should it not?
Aug 07 2016
parent ag0aep6g <anonymous example.com> writes:
On 08/08/2016 02:42 AM, Engine Machine wrote:
 So, what about passing in the lambda verses the temp variable?
Nothing. I didn't see a case where it worked one way but not the other. If you have code where adding a variable makes things work, please post a complete test case. [...]
 My code is as follows and I cannot get 0 parameters working nor passing
 the function in directly. These were my original questions to begin with
 and haven't been answered. Here is the code I am using.

 alias callback(Args...) =  nogc void function(string, int, Args);
  nogc public void foo(Args...)(callback!Args c, Args args, int x) { }

 foo((string s, int i) { }, 1);

 does not work

 nor does

 foo!()((string s, int i) { }, 1);
The second one does work. https://dpaste.dzfl.pl/212b467c62a4
 Ultimately it would also be nice if the template parameters were deduced
 automatically instead of having to specify them. The compiler should be
 able to figure out the types supplied parameters.

 e.g.,

 foo((string s, int i, T x) { }, someT, 1);

 instead of

 foo!(T)((string s, int i, T x) { }, someT, 1);

 should it not?
I think the `callback` template is the problem here. Template instantiation is a one way street. You generally can't answer the question "With what arguments would template Foo need to be instantiated to get result Bar?". For starters, multiple different arguments may map to the same result, making the reverse ambiguous. It works when you skip the `callback` template and put the function/delegate type directly into the signature: ---- nogc public void foo(Args...)(void function(string, int, Args) nogc c, Args args, int x) {} void main() nogc { foo((string s, int i) { }, 1); alias T = float; T someT; foo((string s, int i, T x) { }, someT, 1); } ----
Aug 08 2016