www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Optimizing delegates

reply Ary Borenszweig <ary esperanto.org.ar> writes:
I have this code:

---
import std.stdio;

int foobar(int delegate(int) f) {
   return f(1);
}

int foobar2(string s)() {
   int x = 1;
   mixin("return " ~ s ~ ";");
}

void main() {
   writefln("%d", foobar((int x) { return 2*x; }));
   writefln("%d", foobar2!("9876*x"));
}
---

When I compile it with -O -inline I can see with obj2asm that for the first
writefln the delegate is being called. However, for the second it just passes
9876 to writefln.

From this I can say many things:
 - It seems that if I want hyper-high performance in my code I must use string
mixins because delegate calls, even if they are very simple and the
functions that uses them are also very simple, are not inlined. This has the
drawback that each call to foobar2 with a different string will generate a
different method in the object file.
 - When using string mixins, as mentioned by several others, if I invoke a
function, that function is evaluated in the scope of foobar2, not in the
original scope. That limits a lot what I can pass a string.
 - That means that if I want my users to use either strings or delegates I have
to take that into account, complicating a lot the function signature and
the implementation.
 - That also means I can't always have hyper-high performance because if I need
to do something but I can't do it with a string I have to rely on
delegates, which won't be optimized.
 - Understanding foobar2 is harder than understanding foobar. First, it has two
statements. :-P. Then I have to concatenate the strings in my head to form
the resulting function. And that one is a simple one, so for a complex one it
must be even harder to understand.

From all of these points I can see string mixins are not a very good idea to be
used as callback functions, the main reasons being: it doesn't always work,
it's harder to read and to write and it makes the object file bigger.

So my suggestion is: optimize delegates! Take some time to optimize them to the
maximum and then you won't need string mixins. If foobar here can be
optimized like foobar2, that's it! Why would anyone want to write a function
like foobar2 if the resulting code will be the same?

So here's an idea, it just ocurred to me while writing this post. In the code
above, the compiler sees this:

writefln("%d", foobar((int x) { return 2*x; }));

foobar is this:

int foobar(int delegate(int) f) {
   return f(1);
}

It sees foobar takes a delegate, so what it does it creates a function foobar_1
(or some name not already used) that results from rewriting foobar with the
delegate inlined:

int foobar_1(int delegate(int) f) {
   return 2*1;
}

So now we have:

writefln("%d", foobar_1((int x) { return 2*x; }));

It then optimizes that line and ends up with this:

writefln("%d", 2);

(and I checked if dmd inlines that call, because it passes a delegate it
doesn't use, and yes, it is being inlined).

Then the compiler can discard foobar_1 because it doesn't use it anymore. No
object file bloat, full speed.

What if the delegate is more complex? Let's try:

writefln("%d", foobar((int x) { int a = 10; return a*x; }));

int foobar_1(int delegate(int) f) {
   int delegateResult;
   {
     int a = 10;
     delegateResult = a*1; // 1 was x
   }
   return delegateResult;
}

More complex:

int bar(int y) {
  return y * 3;
}
writefln("%d", foobar((int x) { return bar(x); }));

For this case... I don't know. Maybe it could define bar inside of foobar_1
again, or maybe rewrite foobar_1 to accept another delegate and pass bar to it,
and then reapply this algorithm.

Anyhow... maybe what I say doesn't make sense at all, it's the wrong way to
optimize code or whatever. My point is: if the compiler were smarter I wouldn't
need string mixins to get my code optimized. If you are going to define fancy
functions like map, sort, and other functions that basically receive callback
functions, optimize those callback to the maximum, don't make the users
optimize those callbacks by using string mixins. It's very frustrating for the
user, when she has to sit down and write a high-performance function, to think
"Ok, how can I write this code so the compiler already sees it as being very
easy to optimize?". With D it's not about thinking about the data-structures to
use and the algorithms to use anymore, it's about thinking about writing
code that looks easy to optimize for the compiler. :-(
Dec 19 2010
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2010-12-19 16:32, Ary Borenszweig wrote:
 I have this code:

 ---
 import std.stdio;

 int foobar(int delegate(int) f) {
     return f(1);
 }

 int foobar2(string s)() {
     int x = 1;
     mixin("return " ~ s ~ ";");
 }

 void main() {
     writefln("%d", foobar((int x) { return 2*x; }));
     writefln("%d", foobar2!("9876*x"));
 }
 ---

 When I compile it with -O -inline I can see with obj2asm that for the first
writefln the delegate is being called. However, for the second it just passes
 9876 to writefln.

  From this I can say many things:
   - It seems that if I want hyper-high performance in my code I must use
string mixins because delegate calls, even if they are very simple and the
 functions that uses them are also very simple, are not inlined. This has the
drawback that each call to foobar2 with a different string will generate a
 different method in the object file.
   - When using string mixins, as mentioned by several others, if I invoke a
function, that function is evaluated in the scope of foobar2, not in the
 original scope. That limits a lot what I can pass a string.
   - That means that if I want my users to use either strings or delegates I
have to take that into account, complicating a lot the function signature and
 the implementation.
   - That also means I can't always have hyper-high performance because if I
need to do something but I can't do it with a string I have to rely on
 delegates, which won't be optimized.
   - Understanding foobar2 is harder than understanding foobar. First, it has
two statements. :-P. Then I have to concatenate the strings in my head to form
 the resulting function. And that one is a simple one, so for a complex one it
must be even harder to understand.

  From all of these points I can see string mixins are not a very good idea to
be used as callback functions, the main reasons being: it doesn't always work,
 it's harder to read and to write and it makes the object file bigger.

 So my suggestion is: optimize delegates! Take some time to optimize them to
the maximum and then you won't need string mixins. If foobar here can be
 optimized like foobar2, that's it! Why would anyone want to write a function
like foobar2 if the resulting code will be the same?

 So here's an idea, it just ocurred to me while writing this post. In the code
above, the compiler sees this:

 writefln("%d", foobar((int x) { return 2*x; }));

 foobar is this:

 int foobar(int delegate(int) f) {
     return f(1);
 }

 It sees foobar takes a delegate, so what it does it creates a function
foobar_1 (or some name not already used) that results from rewriting foobar
with the
 delegate inlined:

 int foobar_1(int delegate(int) f) {
     return 2*1;
 }

 So now we have:

 writefln("%d", foobar_1((int x) { return 2*x; }));

 It then optimizes that line and ends up with this:

 writefln("%d", 2);

 (and I checked if dmd inlines that call, because it passes a delegate it
doesn't use, and yes, it is being inlined).

 Then the compiler can discard foobar_1 because it doesn't use it anymore. No
object file bloat, full speed.

 What if the delegate is more complex? Let's try:

 writefln("%d", foobar((int x) { int a = 10; return a*x; }));

 int foobar_1(int delegate(int) f) {
     int delegateResult;
     {
       int a = 10;
       delegateResult = a*1; // 1 was x
     }
     return delegateResult;
 }

 More complex:

 int bar(int y) {
    return y * 3;
 }
 writefln("%d", foobar((int x) { return bar(x); }));

 For this case... I don't know. Maybe it could define bar inside of foobar_1
again, or maybe rewrite foobar_1 to accept another delegate and pass bar to it,
 and then reapply this algorithm.

 Anyhow... maybe what I say doesn't make sense at all, it's the wrong way to
optimize code or whatever. My point is: if the compiler were smarter I wouldn't
 need string mixins to get my code optimized. If you are going to define fancy
functions like map, sort, and other functions that basically receive callback
 functions, optimize those callback to the maximum, don't make the users
optimize those callbacks by using string mixins. It's very frustrating for the
 user, when she has to sit down and write a high-performance function, to think
"Ok, how can I write this code so the compiler already sees it as being very
 easy to optimize?". With D it's not about thinking about the data-structures
to use and the algorithms to use anymore, it's about thinking about writing
 code that looks easy to optimize for the compiler. :-(

I completely agree with this post. -- /Jacob Carlborg
Dec 19 2010
prev sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/19/10 9:32 AM, Ary Borenszweig wrote:
 I have this code:

 ---
 import std.stdio;

 int foobar(int delegate(int) f) {
     return f(1);
 }

 int foobar2(string s)() {
     int x = 1;
     mixin("return " ~ s ~ ";");
 }

 void main() {
     writefln("%d", foobar((int x) { return 2*x; }));
     writefln("%d", foobar2!("9876*x"));
 }
 ---

 When I compile it with -O -inline I can see with obj2asm that for the first
writefln the delegate is being called. However, for the second it just passes
 9876 to writefln.

  From this I can say many things:
   - It seems that if I want hyper-high performance in my code I must use
string mixins because delegate calls, even if they are very simple and the
 functions that uses them are also very simple, are not inlined. This has the
drawback that each call to foobar2 with a different string will generate a
 different method in the object file.

You forgot: writefln("%d", foobar2!((x) { return 2*x; })()); That's a real delegate, not a string, but it will be inlined. Andrei
Dec 19 2010
next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:
 On 12/19/10 9:32 AM, Ary Borenszweig wrote:
 I have this code:

 ---
 import std.stdio;

 int foobar(int delegate(int) f) {
 return f(1);
 }

 int foobar2(string s)() {
 int x = 1;
 mixin("return " ~ s ~ ";");
 }

 void main() {
 writefln("%d", foobar((int x) { return 2*x; }));
 writefln("%d", foobar2!("9876*x"));
 }
 ---

 When I compile it with -O -inline I can see with obj2asm that for the
 first writefln the delegate is being called. However, for the second
 it just passes
 9876 to writefln.

 From this I can say many things:
 - It seems that if I want hyper-high performance in my code I must use
 string mixins because delegate calls, even if they are very simple and
 the
 functions that uses them are also very simple, are not inlined. This
 has the drawback that each call to foobar2 with a different string
 will generate a
 different method in the object file.

You forgot: writefln("%d", foobar2!((x) { return 2*x; })()); That's a real delegate, not a string, but it will be inlined. Andrei

Sorry, I don't understand. I tried these: 1. int foobar3(int delegate(int) f)() { return f(1); } writefln("%d", foobar3!((int x) { return 2*x; })()); => foo.d(12): Error: arithmetic/string type expected for value-parameter, not int delegate(int) 2. int foobar3()(int delegate(int) f) { return f(1); } writefln("%d", foobar3!()((int x) { return 2*x; })); => Works, but it doesn't get inlined. And I tried that "(x) { ... }" syntax and it doesn't work. Sorry, it must be my fault I'm doing something wrong. What's the correct way of writing optimized code in D, code that I'm sure the compiler will know how to optimize?
Dec 19 2010
next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/19/10 10:35 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:
 On 12/19/10 9:32 AM, Ary Borenszweig wrote:
 I have this code:

 ---
 import std.stdio;

 int foobar(int delegate(int) f) {
 return f(1);
 }

 int foobar2(string s)() {
 int x = 1;
 mixin("return " ~ s ~ ";");
 }

 void main() {
 writefln("%d", foobar((int x) { return 2*x; }));
 writefln("%d", foobar2!("9876*x"));
 }
 ---

 When I compile it with -O -inline I can see with obj2asm that for the
 first writefln the delegate is being called. However, for the second
 it just passes
 9876 to writefln.

 From this I can say many things:
 - It seems that if I want hyper-high performance in my code I must use
 string mixins because delegate calls, even if they are very simple and
 the
 functions that uses them are also very simple, are not inlined. This
 has the drawback that each call to foobar2 with a different string
 will generate a
 different method in the object file.

You forgot: writefln("%d", foobar2!((x) { return 2*x; })()); That's a real delegate, not a string, but it will be inlined. Andrei

Sorry, I don't understand. I tried these: 1. int foobar3(int delegate(int) f)() { return f(1); } writefln("%d", foobar3!((int x) { return 2*x; })()); => foo.d(12): Error: arithmetic/string type expected for value-parameter, not int delegate(int) 2. int foobar3()(int delegate(int) f) { return f(1); } writefln("%d", foobar3!()((int x) { return 2*x; })); => Works, but it doesn't get inlined. And I tried that "(x) { ... }" syntax and it doesn't work. Sorry, it must be my fault I'm doing something wrong. What's the correct way of writing optimized code in D, code that I'm sure the compiler will know how to optimize?

void foobar3(alias fun)() { return fun(1); } Andrei
Dec 19 2010
next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
On 12/19/2010 01:44 PM, Andrei Alexandrescu wrote:
 On 12/19/10 10:35 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:
 On 12/19/10 9:32 AM, Ary Borenszweig wrote:
 I have this code:

 ---
 import std.stdio;

 int foobar(int delegate(int) f) {
 return f(1);
 }

 int foobar2(string s)() {
 int x = 1;
 mixin("return " ~ s ~ ";");
 }

 void main() {
 writefln("%d", foobar((int x) { return 2*x; }));
 writefln("%d", foobar2!("9876*x"));
 }
 ---

 When I compile it with -O -inline I can see with obj2asm that for the
 first writefln the delegate is being called. However, for the second
 it just passes
 9876 to writefln.

 From this I can say many things:
 - It seems that if I want hyper-high performance in my code I must use
 string mixins because delegate calls, even if they are very simple and
 the
 functions that uses them are also very simple, are not inlined. This
 has the drawback that each call to foobar2 with a different string
 will generate a
 different method in the object file.

You forgot: writefln("%d", foobar2!((x) { return 2*x; })()); That's a real delegate, not a string, but it will be inlined. Andrei

Sorry, I don't understand. I tried these: 1. int foobar3(int delegate(int) f)() { return f(1); } writefln("%d", foobar3!((int x) { return 2*x; })()); => foo.d(12): Error: arithmetic/string type expected for value-parameter, not int delegate(int) 2. int foobar3()(int delegate(int) f) { return f(1); } writefln("%d", foobar3!()((int x) { return 2*x; })); => Works, but it doesn't get inlined. And I tried that "(x) { ... }" syntax and it doesn't work. Sorry, it must be my fault I'm doing something wrong. What's the correct way of writing optimized code in D, code that I'm sure the compiler will know how to optimize?

void foobar3(alias fun)() { return fun(1); } Andrei

foo.d --- import std.stdio; int foobar3(alias f)() { return f(1); } void main() { writefln("%d", foobar3!((x) { return 9876*x; })()); } asterite deep-water:~/dmd2/linux/bin$ ./dmd foo.d -O -inline asterite deep-water:~/dmd2/linux/bin$ ./obj2asm foo.o | vi - (line 530) _Dmain: push EBP mov EBP,ESP mov EAX,offset FLAT:_D3std5stdio6stdoutS3std5stdio4File SYM32 push dword ptr _TMP0 SYM32[0Eh] push dword ptr _TMP0 SYM32[010h] push 02694h call _D3std5stdio4File19__T8writeflnTAyaTiZ8writeflnMFAyaiZv PC32 xor EAX,EAX pop EBP ret nop nop No, it doesn't seem to get inlined. Luckily. Because if it did get inlined then I would improve DMD by giving an error on this line: int foobar(int delegate(int) f) { ... } foo.d(3): Error: Hey man, what are you doing? Don't you know that if you pass delegates that way they don't get inlined? You should write it this way: "int foobar(alias f)()". That is, of course, if you want your code to be more performant.
Dec 19 2010
next sibling parent Ary Borenszweig <ary esperanto.org.ar> writes:
On 12/19/2010 01:57 PM, Ary Borenszweig wrote:
 On 12/19/2010 01:44 PM, Andrei Alexandrescu wrote:
 On 12/19/10 10:35 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:
 On 12/19/10 9:32 AM, Ary Borenszweig wrote:
 I have this code:

 ---
 import std.stdio;

 int foobar(int delegate(int) f) {
 return f(1);
 }

 int foobar2(string s)() {
 int x = 1;
 mixin("return " ~ s ~ ";");
 }

 void main() {
 writefln("%d", foobar((int x) { return 2*x; }));
 writefln("%d", foobar2!("9876*x"));
 }
 ---

 When I compile it with -O -inline I can see with obj2asm that for the
 first writefln the delegate is being called. However, for the second
 it just passes
 9876 to writefln.

 From this I can say many things:
 - It seems that if I want hyper-high performance in my code I must use
 string mixins because delegate calls, even if they are very simple and
 the
 functions that uses them are also very simple, are not inlined. This
 has the drawback that each call to foobar2 with a different string
 will generate a
 different method in the object file.

You forgot: writefln("%d", foobar2!((x) { return 2*x; })()); That's a real delegate, not a string, but it will be inlined. Andrei

Sorry, I don't understand. I tried these: 1. int foobar3(int delegate(int) f)() { return f(1); } writefln("%d", foobar3!((int x) { return 2*x; })()); => foo.d(12): Error: arithmetic/string type expected for value-parameter, not int delegate(int) 2. int foobar3()(int delegate(int) f) { return f(1); } writefln("%d", foobar3!()((int x) { return 2*x; })); => Works, but it doesn't get inlined. And I tried that "(x) { ... }" syntax and it doesn't work. Sorry, it must be my fault I'm doing something wrong. What's the correct way of writing optimized code in D, code that I'm sure the compiler will know how to optimize?

void foobar3(alias fun)() { return fun(1); } Andrei

foo.d --- import std.stdio; int foobar3(alias f)() { return f(1); } void main() { writefln("%d", foobar3!((x) { return 9876*x; })()); } asterite deep-water:~/dmd2/linux/bin$ ./dmd foo.d -O -inline asterite deep-water:~/dmd2/linux/bin$ ./obj2asm foo.o | vi - (line 530) _Dmain: push EBP mov EBP,ESP mov EAX,offset FLAT:_D3std5stdio6stdoutS3std5stdio4File SYM32 push dword ptr _TMP0 SYM32[0Eh] push dword ptr _TMP0 SYM32[010h] push 02694h call _D3std5stdio4File19__T8writeflnTAyaTiZ8writeflnMFAyaiZv PC32 xor EAX,EAX pop EBP ret nop nop No, it doesn't seem to get inlined. Luckily. Because if it did get inlined then I would improve DMD by giving an error on this line: int foobar(int delegate(int) f) { ... } foo.d(3): Error: Hey man, what are you doing? Don't you know that if you pass delegates that way they don't get inlined? You should write it this way: "int foobar(alias f)()". That is, of course, if you want your code to be more performant.

Oops, sorry, it does get inlined, my mistake. I will submit a patch to DMD right now with the above error.
Dec 19 2010
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Ary Borenszweig" <ary esperanto.org.ar> wrote in message 
news:ieldl1$1ofq$1 digitalmars.com...
 On 12/19/2010 01:44 PM, Andrei Alexandrescu wrote:
 On 12/19/10 10:35 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:
 On 12/19/10 9:32 AM, Ary Borenszweig wrote:
 I have this code:

 ---
 import std.stdio;

 int foobar(int delegate(int) f) {
 return f(1);
 }

 int foobar2(string s)() {
 int x = 1;
 mixin("return " ~ s ~ ";");
 }

 void main() {
 writefln("%d", foobar((int x) { return 2*x; }));
 writefln("%d", foobar2!("9876*x"));
 }
 ---

 When I compile it with -O -inline I can see with obj2asm that for the
 first writefln the delegate is being called. However, for the second
 it just passes
 9876 to writefln.

 From this I can say many things:
 - It seems that if I want hyper-high performance in my code I must use
 string mixins because delegate calls, even if they are very simple and
 the
 functions that uses them are also very simple, are not inlined. This
 has the drawback that each call to foobar2 with a different string
 will generate a
 different method in the object file.

You forgot: writefln("%d", foobar2!((x) { return 2*x; })()); That's a real delegate, not a string, but it will be inlined. Andrei

Sorry, I don't understand. I tried these: 1. int foobar3(int delegate(int) f)() { return f(1); } writefln("%d", foobar3!((int x) { return 2*x; })()); => foo.d(12): Error: arithmetic/string type expected for value-parameter, not int delegate(int) 2. int foobar3()(int delegate(int) f) { return f(1); } writefln("%d", foobar3!()((int x) { return 2*x; })); => Works, but it doesn't get inlined. And I tried that "(x) { ... }" syntax and it doesn't work. Sorry, it must be my fault I'm doing something wrong. What's the correct way of writing optimized code in D, code that I'm sure the compiler will know how to optimize?

void foobar3(alias fun)() { return fun(1); } Andrei

foo.d --- import std.stdio; int foobar3(alias f)() { return f(1); } void main() { writefln("%d", foobar3!((x) { return 9876*x; })()); } asterite deep-water:~/dmd2/linux/bin$ ./dmd foo.d -O -inline asterite deep-water:~/dmd2/linux/bin$ ./obj2asm foo.o | vi - (line 530) _Dmain: push EBP mov EBP,ESP mov EAX,offset FLAT:_D3std5stdio6stdoutS3std5stdio4File SYM32 push dword ptr _TMP0 SYM32[0Eh] push dword ptr _TMP0 SYM32[010h] push 02694h call _D3std5stdio4File19__T8writeflnTAyaTiZ8writeflnMFAyaiZv PC32 xor EAX,EAX pop EBP ret nop nop No, it doesn't seem to get inlined. Luckily. Because if it did get inlined then I would improve DMD by giving an error on this line: int foobar(int delegate(int) f) { ... } foo.d(3): Error: Hey man, what are you doing? Don't you know that if you pass delegates that way they don't get inlined? You should write it this way: "int foobar(alias f)()". That is, of course, if you want your code to be more performant.

It's not completely useless: "int foobar(int delegate(int) f) { }" allows you to choose what delegate to send at run-time. "int foobar3(alias f)() { }" doesn't. (Although, I suppose you might be able to work around that moving the run-time selection from the caller of foobar3 to the delegate passed into "int foobar3(alias f)() { }". Not sure if there are cases where that would be awkward to do.) I will say though, it's a hell of a lot easier to remember the syntax of "int foobar(alias f)()". :)
Dec 19 2010
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/19/10 1:09 PM, Nick Sabalausky wrote:
 It's not completely useless: "int foobar(int delegate(int) f) { }" allows
 you to choose what delegate to send at run-time. "int foobar3(alias f)()
 { }" doesn't. (Although, I suppose you might be able to work around that
 moving the run-time selection from the caller of foobar3 to the delegate
 passed into "int foobar3(alias f)() { }". Not sure if there are cases where
 that would be awkward to do.)

In fact you can select the alias at runtime, which is quite a trick. Andrei
Dec 19 2010
prev sibling next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
On 12/19/2010 01:44 PM, Andrei Alexandrescu wrote:
 On 12/19/10 10:35 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:
 On 12/19/10 9:32 AM, Ary Borenszweig wrote:
 I have this code:

 ---
 import std.stdio;

 int foobar(int delegate(int) f) {
 return f(1);
 }

 int foobar2(string s)() {
 int x = 1;
 mixin("return " ~ s ~ ";");
 }

 void main() {
 writefln("%d", foobar((int x) { return 2*x; }));
 writefln("%d", foobar2!("9876*x"));
 }
 ---

 When I compile it with -O -inline I can see with obj2asm that for the
 first writefln the delegate is being called. However, for the second
 it just passes
 9876 to writefln.

 From this I can say many things:
 - It seems that if I want hyper-high performance in my code I must use
 string mixins because delegate calls, even if they are very simple and
 the
 functions that uses them are also very simple, are not inlined. This
 has the drawback that each call to foobar2 with a different string
 will generate a
 different method in the object file.

You forgot: writefln("%d", foobar2!((x) { return 2*x; })()); That's a real delegate, not a string, but it will be inlined. Andrei

Sorry, I don't understand. I tried these: 1. int foobar3(int delegate(int) f)() { return f(1); } writefln("%d", foobar3!((int x) { return 2*x; })()); => foo.d(12): Error: arithmetic/string type expected for value-parameter, not int delegate(int) 2. int foobar3()(int delegate(int) f) { return f(1); } writefln("%d", foobar3!()((int x) { return 2*x; })); => Works, but it doesn't get inlined. And I tried that "(x) { ... }" syntax and it doesn't work. Sorry, it must be my fault I'm doing something wrong. What's the correct way of writing optimized code in D, code that I'm sure the compiler will know how to optimize?

void foobar3(alias fun)() { return fun(1); } Andrei

This of course has the following problem: int foobar2(int delegate(int x) f) { } foobar2((int x, int y) { ... }); Error: function foobar2 (int delegate(int) f) is not callable using argument types (int delegate(int x, int y)) --- int foobar3(alias f)() { f(1); } foobar3((x, y) { ... }); foo.d(8): Error: template foo.main.__dgliteral1(__T2,__T3) does not match any function template declaration foo.d(8): Error: template foo.main.__dgliteral1(__T2,__T3) cannot deduce template function from argument types !()(int) foo.d(12): Error: template instance foo.main.foobar3!(__dgliteral1) error instantiating So I have to go to foo.d(8) to see what the problem is, understand what is being invoked (in this case it was easy but it get can harder), or otherwise say "Hey, the one that implemented foo, please do a static assert msg if f is not what you expect". Basically "Implement the error message that the compiler would have given you for free if you didn't use a template".
Dec 19 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/19/10 11:13 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:44 PM, Andrei Alexandrescu wrote:
 On 12/19/10 10:35 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:
 On 12/19/10 9:32 AM, Ary Borenszweig wrote:
 I have this code:

 ---
 import std.stdio;

 int foobar(int delegate(int) f) {
 return f(1);
 }

 int foobar2(string s)() {
 int x = 1;
 mixin("return " ~ s ~ ";");
 }

 void main() {
 writefln("%d", foobar((int x) { return 2*x; }));
 writefln("%d", foobar2!("9876*x"));
 }
 ---

 When I compile it with -O -inline I can see with obj2asm that for the
 first writefln the delegate is being called. However, for the second
 it just passes
 9876 to writefln.

 From this I can say many things:
 - It seems that if I want hyper-high performance in my code I must use
 string mixins because delegate calls, even if they are very simple and
 the
 functions that uses them are also very simple, are not inlined. This
 has the drawback that each call to foobar2 with a different string
 will generate a
 different method in the object file.

You forgot: writefln("%d", foobar2!((x) { return 2*x; })()); That's a real delegate, not a string, but it will be inlined. Andrei

Sorry, I don't understand. I tried these: 1. int foobar3(int delegate(int) f)() { return f(1); } writefln("%d", foobar3!((int x) { return 2*x; })()); => foo.d(12): Error: arithmetic/string type expected for value-parameter, not int delegate(int) 2. int foobar3()(int delegate(int) f) { return f(1); } writefln("%d", foobar3!()((int x) { return 2*x; })); => Works, but it doesn't get inlined. And I tried that "(x) { ... }" syntax and it doesn't work. Sorry, it must be my fault I'm doing something wrong. What's the correct way of writing optimized code in D, code that I'm sure the compiler will know how to optimize?

void foobar3(alias fun)() { return fun(1); } Andrei

This of course has the following problem: int foobar2(int delegate(int x) f) { } foobar2((int x, int y) { ... }); Error: function foobar2 (int delegate(int) f) is not callable using argument types (int delegate(int x, int y)) --- int foobar3(alias f)() { f(1); } foobar3((x, y) { ... }); foo.d(8): Error: template foo.main.__dgliteral1(__T2,__T3) does not match any function template declaration foo.d(8): Error: template foo.main.__dgliteral1(__T2,__T3) cannot deduce template function from argument types !()(int) foo.d(12): Error: template instance foo.main.foobar3!(__dgliteral1) error instantiating So I have to go to foo.d(8) to see what the problem is, understand what is being invoked (in this case it was easy but it get can harder), or otherwise say "Hey, the one that implemented foo, please do a static assert msg if f is not what you expect". Basically "Implement the error message that the compiler would have given you for free if you didn't use a template".

Template constraints are meant to assuage that problem. Inlining delegates is technically much more difficult than inlining aliases. This is because a different function will be generated for each alias argument, whereas only one function would be used for all delegates. There are techniques to address that in the compiler, but they are rather complex. Andrei
Dec 19 2010
next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/19/10 11:17 AM, Andrei Alexandrescu wrote:
 Inlining delegates is technically much more difficult than inlining
 aliases. This is because a different function will be generated for each
 alias argument, whereas only one function would be used for all
 delegates. There are techniques to address that in the compiler, but
 they are rather complex.

Let me add that good Lisp programmers understand that very well. Seasoned Lisp experts seldom use the textbook lambdas as can be seen in all Lisp books and that rank and file Lisp programmers use everywhere. Experts use macros because they understand their advantages (of which speed is an important one). Andrei
Dec 19 2010
prev sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
On 12/19/2010 02:17 PM, Andrei Alexandrescu wrote:
 On 12/19/10 11:13 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:44 PM, Andrei Alexandrescu wrote:
 On 12/19/10 10:35 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:
 On 12/19/10 9:32 AM, Ary Borenszweig wrote:
 I have this code:

 ---
 import std.stdio;

 int foobar(int delegate(int) f) {
 return f(1);
 }

 int foobar2(string s)() {
 int x = 1;
 mixin("return " ~ s ~ ";");
 }

 void main() {
 writefln("%d", foobar((int x) { return 2*x; }));
 writefln("%d", foobar2!("9876*x"));
 }
 ---

 When I compile it with -O -inline I can see with obj2asm that for the
 first writefln the delegate is being called. However, for the second
 it just passes
 9876 to writefln.

 From this I can say many things:
 - It seems that if I want hyper-high performance in my code I must
 use
 string mixins because delegate calls, even if they are very simple
 and
 the
 functions that uses them are also very simple, are not inlined. This
 has the drawback that each call to foobar2 with a different string
 will generate a
 different method in the object file.

You forgot: writefln("%d", foobar2!((x) { return 2*x; })()); That's a real delegate, not a string, but it will be inlined. Andrei

Sorry, I don't understand. I tried these: 1. int foobar3(int delegate(int) f)() { return f(1); } writefln("%d", foobar3!((int x) { return 2*x; })()); => foo.d(12): Error: arithmetic/string type expected for value-parameter, not int delegate(int) 2. int foobar3()(int delegate(int) f) { return f(1); } writefln("%d", foobar3!()((int x) { return 2*x; })); => Works, but it doesn't get inlined. And I tried that "(x) { ... }" syntax and it doesn't work. Sorry, it must be my fault I'm doing something wrong. What's the correct way of writing optimized code in D, code that I'm sure the compiler will know how to optimize?

void foobar3(alias fun)() { return fun(1); } Andrei

This of course has the following problem: int foobar2(int delegate(int x) f) { } foobar2((int x, int y) { ... }); Error: function foobar2 (int delegate(int) f) is not callable using argument types (int delegate(int x, int y)) --- int foobar3(alias f)() { f(1); } foobar3((x, y) { ... }); foo.d(8): Error: template foo.main.__dgliteral1(__T2,__T3) does not match any function template declaration foo.d(8): Error: template foo.main.__dgliteral1(__T2,__T3) cannot deduce template function from argument types !()(int) foo.d(12): Error: template instance foo.main.foobar3!(__dgliteral1) error instantiating So I have to go to foo.d(8) to see what the problem is, understand what is being invoked (in this case it was easy but it get can harder), or otherwise say "Hey, the one that implemented foo, please do a static assert msg if f is not what you expect". Basically "Implement the error message that the compiler would have given you for free if you didn't use a template".

Template constraints are meant to assuage that problem. Inlining delegates is technically much more difficult than inlining aliases. This is because a different function will be generated for each alias argument, whereas only one function would be used for all delegates. There are techniques to address that in the compiler, but they are rather complex. Andrei

I understand. So why do I have to use a whole different syntax to make something accepting a delegate a function or a template? Why can't this be accepted? int foobar2(int delegate(int x) f)() { } and let the compiler interpret it as: int foobar2(alias f) if ("the correct constraint which I don't want to learn how to write because the above SHOULD work") { } ?
Dec 19 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/19/10 11:23 AM, Ary Borenszweig wrote:
 On 12/19/2010 02:17 PM, Andrei Alexandrescu wrote:
 On 12/19/10 11:13 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:44 PM, Andrei Alexandrescu wrote:
 On 12/19/10 10:35 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:
 On 12/19/10 9:32 AM, Ary Borenszweig wrote:
 I have this code:

 ---
 import std.stdio;

 int foobar(int delegate(int) f) {
 return f(1);
 }

 int foobar2(string s)() {
 int x = 1;
 mixin("return " ~ s ~ ";");
 }

 void main() {
 writefln("%d", foobar((int x) { return 2*x; }));
 writefln("%d", foobar2!("9876*x"));
 }
 ---

 When I compile it with -O -inline I can see with obj2asm that for
 the
 first writefln the delegate is being called. However, for the second
 it just passes
 9876 to writefln.

 From this I can say many things:
 - It seems that if I want hyper-high performance in my code I must
 use
 string mixins because delegate calls, even if they are very simple
 and
 the
 functions that uses them are also very simple, are not inlined. This
 has the drawback that each call to foobar2 with a different string
 will generate a
 different method in the object file.

You forgot: writefln("%d", foobar2!((x) { return 2*x; })()); That's a real delegate, not a string, but it will be inlined. Andrei

Sorry, I don't understand. I tried these: 1. int foobar3(int delegate(int) f)() { return f(1); } writefln("%d", foobar3!((int x) { return 2*x; })()); => foo.d(12): Error: arithmetic/string type expected for value-parameter, not int delegate(int) 2. int foobar3()(int delegate(int) f) { return f(1); } writefln("%d", foobar3!()((int x) { return 2*x; })); => Works, but it doesn't get inlined. And I tried that "(x) { ... }" syntax and it doesn't work. Sorry, it must be my fault I'm doing something wrong. What's the correct way of writing optimized code in D, code that I'm sure the compiler will know how to optimize?

void foobar3(alias fun)() { return fun(1); } Andrei

This of course has the following problem: int foobar2(int delegate(int x) f) { } foobar2((int x, int y) { ... }); Error: function foobar2 (int delegate(int) f) is not callable using argument types (int delegate(int x, int y)) --- int foobar3(alias f)() { f(1); } foobar3((x, y) { ... }); foo.d(8): Error: template foo.main.__dgliteral1(__T2,__T3) does not match any function template declaration foo.d(8): Error: template foo.main.__dgliteral1(__T2,__T3) cannot deduce template function from argument types !()(int) foo.d(12): Error: template instance foo.main.foobar3!(__dgliteral1) error instantiating So I have to go to foo.d(8) to see what the problem is, understand what is being invoked (in this case it was easy but it get can harder), or otherwise say "Hey, the one that implemented foo, please do a static assert msg if f is not what you expect". Basically "Implement the error message that the compiler would have given you for free if you didn't use a template".

Template constraints are meant to assuage that problem. Inlining delegates is technically much more difficult than inlining aliases. This is because a different function will be generated for each alias argument, whereas only one function would be used for all delegates. There are techniques to address that in the compiler, but they are rather complex. Andrei

I understand. So why do I have to use a whole different syntax to make something accepting a delegate a function or a template? Why can't this be accepted? int foobar2(int delegate(int x) f)() { } and let the compiler interpret it as: int foobar2(alias f) if ("the correct constraint which I don't want to learn how to write because the above SHOULD work") { } ?

Because that would be unlike everything else in D. Andrei
Dec 19 2010
parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
On 12/19/2010 02:28 PM, Andrei Alexandrescu wrote:
 On 12/19/10 11:23 AM, Ary Borenszweig wrote:
 On 12/19/2010 02:17 PM, Andrei Alexandrescu wrote:
 On 12/19/10 11:13 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:44 PM, Andrei Alexandrescu wrote:
 On 12/19/10 10:35 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:
 On 12/19/10 9:32 AM, Ary Borenszweig wrote:
 I have this code:

 ---
 import std.stdio;

 int foobar(int delegate(int) f) {
 return f(1);
 }

 int foobar2(string s)() {
 int x = 1;
 mixin("return " ~ s ~ ";");
 }

 void main() {
 writefln("%d", foobar((int x) { return 2*x; }));
 writefln("%d", foobar2!("9876*x"));
 }
 ---

 When I compile it with -O -inline I can see with obj2asm that for
 the
 first writefln the delegate is being called. However, for the
 second
 it just passes
 9876 to writefln.

 From this I can say many things:
 - It seems that if I want hyper-high performance in my code I must
 use
 string mixins because delegate calls, even if they are very simple
 and
 the
 functions that uses them are also very simple, are not inlined.
 This
 has the drawback that each call to foobar2 with a different string
 will generate a
 different method in the object file.

You forgot: writefln("%d", foobar2!((x) { return 2*x; })()); That's a real delegate, not a string, but it will be inlined. Andrei

Sorry, I don't understand. I tried these: 1. int foobar3(int delegate(int) f)() { return f(1); } writefln("%d", foobar3!((int x) { return 2*x; })()); => foo.d(12): Error: arithmetic/string type expected for value-parameter, not int delegate(int) 2. int foobar3()(int delegate(int) f) { return f(1); } writefln("%d", foobar3!()((int x) { return 2*x; })); => Works, but it doesn't get inlined. And I tried that "(x) { ... }" syntax and it doesn't work. Sorry, it must be my fault I'm doing something wrong. What's the correct way of writing optimized code in D, code that I'm sure the compiler will know how to optimize?

void foobar3(alias fun)() { return fun(1); } Andrei

This of course has the following problem: int foobar2(int delegate(int x) f) { } foobar2((int x, int y) { ... }); Error: function foobar2 (int delegate(int) f) is not callable using argument types (int delegate(int x, int y)) --- int foobar3(alias f)() { f(1); } foobar3((x, y) { ... }); foo.d(8): Error: template foo.main.__dgliteral1(__T2,__T3) does not match any function template declaration foo.d(8): Error: template foo.main.__dgliteral1(__T2,__T3) cannot deduce template function from argument types !()(int) foo.d(12): Error: template instance foo.main.foobar3!(__dgliteral1) error instantiating So I have to go to foo.d(8) to see what the problem is, understand what is being invoked (in this case it was easy but it get can harder), or otherwise say "Hey, the one that implemented foo, please do a static assert msg if f is not what you expect". Basically "Implement the error message that the compiler would have given you for free if you didn't use a template".

Template constraints are meant to assuage that problem. Inlining delegates is technically much more difficult than inlining aliases. This is because a different function will be generated for each alias argument, whereas only one function would be used for all delegates. There are techniques to address that in the compiler, but they are rather complex. Andrei

I understand. So why do I have to use a whole different syntax to make something accepting a delegate a function or a template? Why can't this be accepted? int foobar2(int delegate(int x) f)() { } and let the compiler interpret it as: int foobar2(alias f) if ("the correct constraint which I don't want to learn how to write because the above SHOULD work") { } ?

Because that would be unlike everything else in D. Andrei

What do you mean? It's not unlike everything else in D. It's *exactly* like a function call in D.
Dec 19 2010
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 12/19/10 11:35 AM, Ary Borenszweig wrote:
 On 12/19/2010 02:28 PM, Andrei Alexandrescu wrote:
 On 12/19/10 11:23 AM, Ary Borenszweig wrote:
 On 12/19/2010 02:17 PM, Andrei Alexandrescu wrote:
 On 12/19/10 11:13 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:44 PM, Andrei Alexandrescu wrote:
 On 12/19/10 10:35 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:
 On 12/19/10 9:32 AM, Ary Borenszweig wrote:
 I have this code:

 ---
 import std.stdio;

 int foobar(int delegate(int) f) {
 return f(1);
 }

 int foobar2(string s)() {
 int x = 1;
 mixin("return " ~ s ~ ";");
 }

 void main() {
 writefln("%d", foobar((int x) { return 2*x; }));
 writefln("%d", foobar2!("9876*x"));
 }
 ---

 When I compile it with -O -inline I can see with obj2asm that for
 the
 first writefln the delegate is being called. However, for the
 second
 it just passes
 9876 to writefln.

 From this I can say many things:
 - It seems that if I want hyper-high performance in my code I must
 use
 string mixins because delegate calls, even if they are very simple
 and
 the
 functions that uses them are also very simple, are not inlined.
 This
 has the drawback that each call to foobar2 with a different string
 will generate a
 different method in the object file.

You forgot: writefln("%d", foobar2!((x) { return 2*x; })()); That's a real delegate, not a string, but it will be inlined. Andrei

Sorry, I don't understand. I tried these: 1. int foobar3(int delegate(int) f)() { return f(1); } writefln("%d", foobar3!((int x) { return 2*x; })()); => foo.d(12): Error: arithmetic/string type expected for value-parameter, not int delegate(int) 2. int foobar3()(int delegate(int) f) { return f(1); } writefln("%d", foobar3!()((int x) { return 2*x; })); => Works, but it doesn't get inlined. And I tried that "(x) { ... }" syntax and it doesn't work. Sorry, it must be my fault I'm doing something wrong. What's the correct way of writing optimized code in D, code that I'm sure the compiler will know how to optimize?

void foobar3(alias fun)() { return fun(1); } Andrei

This of course has the following problem: int foobar2(int delegate(int x) f) { } foobar2((int x, int y) { ... }); Error: function foobar2 (int delegate(int) f) is not callable using argument types (int delegate(int x, int y)) --- int foobar3(alias f)() { f(1); } foobar3((x, y) { ... }); foo.d(8): Error: template foo.main.__dgliteral1(__T2,__T3) does not match any function template declaration foo.d(8): Error: template foo.main.__dgliteral1(__T2,__T3) cannot deduce template function from argument types !()(int) foo.d(12): Error: template instance foo.main.foobar3!(__dgliteral1) error instantiating So I have to go to foo.d(8) to see what the problem is, understand what is being invoked (in this case it was easy but it get can harder), or otherwise say "Hey, the one that implemented foo, please do a static assert msg if f is not what you expect". Basically "Implement the error message that the compiler would have given you for free if you didn't use a template".

Template constraints are meant to assuage that problem. Inlining delegates is technically much more difficult than inlining aliases. This is because a different function will be generated for each alias argument, whereas only one function would be used for all delegates. There are techniques to address that in the compiler, but they are rather complex. Andrei

I understand. So why do I have to use a whole different syntax to make something accepting a delegate a function or a template? Why can't this be accepted? int foobar2(int delegate(int x) f)() { } and let the compiler interpret it as: int foobar2(alias f) if ("the correct constraint which I don't want to learn how to write because the above SHOULD work") { } ?

Because that would be unlike everything else in D. Andrei

What do you mean? It's not unlike everything else in D. It's *exactly* like a function call in D.

No function definition expands into a template. Andrei
Dec 19 2010
next sibling parent "Nick Sabalausky" <a a.a> writes:
"spir" <denis.spir gmail.com> wrote in message 
news:mailman.35.1292785009.4748.digitalmars-d puremagic.com...
Don't you all find it annoying to constantly keep whole threads, most of 
which are to your answer irrelevant, just to reply a few word?. Please 
instead keep only relevant snippet(s). Here the kept text is about 5kb.

Scrolling is very, very easy, and 5k is tiny.
Dec 19 2010
prev sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
On 12/19/2010 03:43 PM, Andrei Alexandrescu wrote:
 On 12/19/10 11:35 AM, Ary Borenszweig wrote:
 On 12/19/2010 02:28 PM, Andrei Alexandrescu wrote:
 On 12/19/10 11:23 AM, Ary Borenszweig wrote:
 On 12/19/2010 02:17 PM, Andrei Alexandrescu wrote:
 On 12/19/10 11:13 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:44 PM, Andrei Alexandrescu wrote:
 On 12/19/10 10:35 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:
 On 12/19/10 9:32 AM, Ary Borenszweig wrote:
 I have this code:

 ---
 import std.stdio;

 int foobar(int delegate(int) f) {
 return f(1);
 }

 int foobar2(string s)() {
 int x = 1;
 mixin("return " ~ s ~ ";");
 }

 void main() {
 writefln("%d", foobar((int x) { return 2*x; }));
 writefln("%d", foobar2!("9876*x"));
 }
 ---

 When I compile it with -O -inline I can see with obj2asm that for
 the
 first writefln the delegate is being called. However, for the
 second
 it just passes
 9876 to writefln.

 From this I can say many things:
 - It seems that if I want hyper-high performance in my code I
 must
 use
 string mixins because delegate calls, even if they are very
 simple
 and
 the
 functions that uses them are also very simple, are not inlined.
 This
 has the drawback that each call to foobar2 with a different
 string
 will generate a
 different method in the object file.

You forgot: writefln("%d", foobar2!((x) { return 2*x; })()); That's a real delegate, not a string, but it will be inlined. Andrei

Sorry, I don't understand. I tried these: 1. int foobar3(int delegate(int) f)() { return f(1); } writefln("%d", foobar3!((int x) { return 2*x; })()); => foo.d(12): Error: arithmetic/string type expected for value-parameter, not int delegate(int) 2. int foobar3()(int delegate(int) f) { return f(1); } writefln("%d", foobar3!()((int x) { return 2*x; })); => Works, but it doesn't get inlined. And I tried that "(x) { ... }" syntax and it doesn't work. Sorry, it must be my fault I'm doing something wrong. What's the correct way of writing optimized code in D, code that I'm sure the compiler will know how to optimize?

void foobar3(alias fun)() { return fun(1); } Andrei

This of course has the following problem: int foobar2(int delegate(int x) f) { } foobar2((int x, int y) { ... }); Error: function foobar2 (int delegate(int) f) is not callable using argument types (int delegate(int x, int y)) --- int foobar3(alias f)() { f(1); } foobar3((x, y) { ... }); foo.d(8): Error: template foo.main.__dgliteral1(__T2,__T3) does not match any function template declaration foo.d(8): Error: template foo.main.__dgliteral1(__T2,__T3) cannot deduce template function from argument types !()(int) foo.d(12): Error: template instance foo.main.foobar3!(__dgliteral1) error instantiating So I have to go to foo.d(8) to see what the problem is, understand what is being invoked (in this case it was easy but it get can harder), or otherwise say "Hey, the one that implemented foo, please do a static assert msg if f is not what you expect". Basically "Implement the error message that the compiler would have given you for free if you didn't use a template".

Template constraints are meant to assuage that problem. Inlining delegates is technically much more difficult than inlining aliases. This is because a different function will be generated for each alias argument, whereas only one function would be used for all delegates. There are techniques to address that in the compiler, but they are rather complex. Andrei

I understand. So why do I have to use a whole different syntax to make something accepting a delegate a function or a template? Why can't this be accepted? int foobar2(int delegate(int x) f)() { } and let the compiler interpret it as: int foobar2(alias f) if ("the correct constraint which I don't want to learn how to write because the above SHOULD work") { } ?

Because that would be unlike everything else in D. Andrei

What do you mean? It's not unlike everything else in D. It's *exactly* like a function call in D.

No function definition expands into a template. Andrei

But that is a template: int foobar2(int delegate(int x) f)() { } It's a template that doesn't work because I have to write it in a different way. Sorry, I tried many different template constraints and none of them work. I tried these: int foobar2(alias f)() if (typeof(f) == typeid(int delegate(int x))) if (is(typeof(f) == int delegate(int))) if (is(typeof(f) == delegate)) What do I have to write to make it work?
Dec 19 2010
parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2010-12-19 15:30:50 -0500, Ary Borenszweig <ary esperanto.org.ar> said:

 But that is a template:
 
 int foobar2(int delegate(int x) f)() {
 }
 
 It's a template that doesn't work because I have to write it in a 
 different way. Sorry, I tried many different template constraints and 
 none of them work.
 
 I tried these:
 
 int foobar2(alias f)()
    if (typeof(f) == typeid(int delegate(int x)))
    if (is(typeof(f) == int delegate(int)))
    if (is(typeof(f) == delegate))
 
 What do I have to write to make it work?

int foobar2(alias f)() if (is(typeof(f(int.init)) == int)) On the plus side, it'll not only work with delegates but also with regular functions, template functions, and objects with an opCall member. If you absolutely want to limit it to a delegate, you can try this: int foobar2(alias f)() if (is(typeof(&f) == int delegate(int))) -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Dec 19 2010
parent Ary Borenszweig <ary esperanto.org.ar> writes:
On 12/19/2010 07:54 PM, Andrej Mitrovic wrote:
 There's an isDelegate template function in std.traits, but I think
 there's some kind of bug there. I've reported it and I'm waiting for
 answers.

 Otherwise there are other functions you can use, e.g.:

 isSomeFunction(T), isCallable(T), is(FunctionTypeOf(T) == delegate)..

 On 12/19/10, Michel Fortin<michel.fortin michelf.com>  wrote:
 On 2010-12-19 15:30:50 -0500, Ary Borenszweig<ary esperanto.org.ar>  said:

 But that is a template:

 int foobar2(int delegate(int x) f)() {
 }

 It's a template that doesn't work because I have to write it in a
 different way. Sorry, I tried many different template constraints and
 none of them work.

 I tried these:

 int foobar2(alias f)()
     if (typeof(f) == typeid(int delegate(int x)))
     if (is(typeof(f) == int delegate(int)))
     if (is(typeof(f) == delegate))

 What do I have to write to make it work?

int foobar2(alias f)() if (is(typeof(f(int.init)) == int)) On the plus side, it'll not only work with delegates but also with regular functions, template functions, and objects with an opCall member. If you absolutely want to limit it to a delegate, you can try this: int foobar2(alias f)() if (is(typeof(&f) == int delegate(int))) -- Michel Fortin michel.fortin michelf.com http://michelf.com/


What I don't like about that is that it's not consistent. I can write: int foo(int x)() { } but I cannot write: int foo(int delegate(int) x)() { } Well, I can, and the compiler gives me an error saying "No, you can't do that". I have to dig std.traits code or use one of those killer 4 level nested parenthesis to tell the compiler "this is a delegate". With what I'm telling it the compiler already sees I want to define a template that accepts a delegate. Don't you all think it's more consistent this way? I know there is a way to do it, but having to learn 10 ways to write things depending on what type I'm going to use is very time consuming. And before you tell me "In ruby there are 10 different ways to do X", that's fine, because all of them work. That's consistency. No matter how I express myself to the compiler/language, it works. But if the compiler starts telling me "Oh, you know, for this type I don't like this syntax, please use another one"... Same goes with "a>b". It's not consistent. It sometimes doesn't work.
Dec 19 2010
prev sibling parent loser <noneedtotalkanymore to.me> writes:
Daniel Gibson Wrote:

 On Sun, Dec 19, 2010 at 5:44 PM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 On 12/19/10 10:35 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:
 On 12/19/10 9:32 AM, Ary Borenszweig wrote:
 I have this code:

 ---
 import std.stdio;

 int foobar(int delegate(int) f) {
 return f(1);
 }

 int foobar2(string s)() {
 int x = 1;
 mixin("return " ~ s ~ ";");
 }

 void main() {
 writefln("%d", foobar((int x) { return 2*x; }));
 writefln("%d", foobar2!("9876*x"));
 }
 ---

 When I compile it with -O -inline I can see with obj2asm that for the
 first writefln the delegate is being called. However, for the second
 it just passes
 9876 to writefln.

 From this I can say many things:
 - It seems that if I want hyper-high performance in my code I must use
 string mixins because delegate calls, even if they are very simple and
 the
 functions that uses them are also very simple, are not inlined. This
 has the drawback that each call to foobar2 with a different string
 will generate a
 different method in the object file.

You forgot: writefln("%d", foobar2!((x) { return 2*x; })()); That's a real delegate, not a string, but it will be inlined. Andrei

Sorry, I don't understand. I tried these: 1. int foobar3(int delegate(int) f)() { return f(1); } writefln("%d", foobar3!((int x) { return 2*x; })()); => foo.d(12): Error: arithmetic/string type expected for value-parameter, not int delegate(int) 2. int foobar3()(int delegate(int) f) { return f(1); } writefln("%d", foobar3!()((int x) { return 2*x; })); => Works, but it doesn't get inlined. And I tried that "(x) { ... }" syntax and it doesn't work. Sorry, it must be my fault I'm doing something wrong. What's the correct way of writing optimized code in D, code that I'm sure the compiler will know how to optimize?

void foobar3(alias fun)() {    return fun(1); } Andrei

I think using an alias makes the code less readable. "int foobar(int delegate(int) f)" tells you that the argument should be (a delegate of) a function that accepts an int and returns an int. "foobar3(alias fun)()" tells you almost nothing. You know that some kind of template parameter is expected, but not if it's a function or whatever, and even less what signature that function should have. IMHO some other syntax than just "alias fun" should be used for this purpose (inlined delegates known at compile time) - some syntax that documents the signature of the expected function, like with real delegates.

Hear, hear. Another problem with this approach I couldn't even think of. With luck, illegal code may compile. You have no clean way to enforce/document the domain of the comparator/predicate.
Dec 19 2010
prev sibling parent Max Samukha <spambox d-coding.com> writes:
On 12/19/2010 06:35 PM, Ary Borenszweig wrote:
 On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:
 On 12/19/10 9:32 AM, Ary Borenszweig wrote:
 I have this code:

 ---
 import std.stdio;

 int foobar(int delegate(int) f) {
 return f(1);
 }

 int foobar2(string s)() {
 int x = 1;
 mixin("return " ~ s ~ ";");
 }

 void main() {
 writefln("%d", foobar((int x) { return 2*x; }));
 writefln("%d", foobar2!("9876*x"));
 }
 ---

 When I compile it with -O -inline I can see with obj2asm that for the
 first writefln the delegate is being called. However, for the second
 it just passes
 9876 to writefln.

 From this I can say many things:
 - It seems that if I want hyper-high performance in my code I must use
 string mixins because delegate calls, even if they are very simple and
 the
 functions that uses them are also very simple, are not inlined. This
 has the drawback that each call to foobar2 with a different string
 will generate a
 different method in the object file.

You forgot: writefln("%d", foobar2!((x) { return 2*x; })()); That's a real delegate, not a string, but it will be inlined. Andrei

Sorry, I don't understand. I tried these: 1. int foobar3(int delegate(int) f)() { return f(1); } writefln("%d", foobar3!((int x) { return 2*x; })()); => foo.d(12): Error: arithmetic/string type expected for value-parameter, not int delegate(int)

int foobar3(alias f)() { return f(1); } alias template parameters accept everything that variadic template parameters do (including delegate literals) with the unfortunate exception of basic types :-O.
Dec 19 2010
prev sibling next sibling parent spir <denis.spir gmail.com> writes:
On Sun, 19 Dec 2010 12:43:23 -0600
Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote:

 On 12/19/10 11:35 AM, Ary Borenszweig wrote:
 On 12/19/2010 02:28 PM, Andrei Alexandrescu wrote:
 On 12/19/10 11:23 AM, Ary Borenszweig wrote:
 On 12/19/2010 02:17 PM, Andrei Alexandrescu wrote:
 On 12/19/10 11:13 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:44 PM, Andrei Alexandrescu wrote:
 On 12/19/10 10:35 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:
 On 12/19/10 9:32 AM, Ary Borenszweig wrote:
 I have this code:

 ---
 import std.stdio;

 int foobar(int delegate(int) f) {
 return f(1);
 }

 int foobar2(string s)() {
 int x =3D 1;
 mixin("return " ~ s ~ ";");
 }

 void main() {
 writefln("%d", foobar((int x) { return 2*x; }));
 writefln("%d", foobar2!("9876*x"));
 }
 ---

 When I compile it with -O -inline I can see with obj2asm that f=










 the
 first writefln the delegate is being called. However, for the
 second
 it just passes
 9876 to writefln.

 From this I can say many things:
 - It seems that if I want hyper-high performance in my code I m=










 use
 string mixins because delegate calls, even if they are very sim=










 and
 the
 functions that uses them are also very simple, are not inlined.
 This
 has the drawback that each call to foobar2 with a different str=










 will generate a
 different method in the object file.

You forgot: writefln("%d", foobar2!((x) { return 2*x; })()); That's a real delegate, not a string, but it will be inlined. Andrei

Sorry, I don't understand. I tried these: 1. int foobar3(int delegate(int) f)() { return f(1); } writefln("%d", foobar3!((int x) { return 2*x; })()); =3D> foo.d(12): Error: arithmetic/string type expected for value-parameter, not int delegate(int) 2. int foobar3()(int delegate(int) f) { return f(1); } writefln("%d", foobar3!()((int x) { return 2*x; })); =3D> Works, but it doesn't get inlined. And I tried that "(x) { ... }" syntax and it doesn't work. Sorry, it must be my fault I'm doing something wrong. What's the correct way of writing optimized code in D, code that I'm sure the compil=








 will
 know how to optimize?

void foobar3(alias fun)() { return fun(1); } Andrei

This of course has the following problem: int foobar2(int delegate(int x) f) { } foobar2((int x, int y) { ... }); Error: function foobar2 (int delegate(int) f) is not callable using argument types (int delegate(int x, int y)) --- int foobar3(alias f)() { f(1); } foobar3((x, y) { ... }); foo.d(8): Error: template foo.main.__dgliteral1(__T2,__T3) does not match any function template declaration foo.d(8): Error: template foo.main.__dgliteral1(__T2,__T3) cannot deduce template function from argument types !()(int) foo.d(12): Error: template instance foo.main.foobar3!(__dgliteral1) error instantiating So I have to go to foo.d(8) to see what the problem is, understand what is being invoked (in this case it was easy but it get can harder), =






 otherwise say "Hey, the one that implemented foo, please do a static
 assert msg if f is not what you expect". Basically "Implement the
 error
 message that the compiler would have given you for free if you didn=






 use a template".

Template constraints are meant to assuage that problem. Inlining delegates is technically much more difficult than inlining aliases. This is because a different function will be generated for each alias argument, whereas only one function would be used for all delegates. There are techniques to address that in the compiler, but they are rather complex. Andrei

I understand. So why do I have to use a whole different syntax to make something accepting a delegate a function or a template? Why can't this be accepted? int foobar2(int delegate(int x) f)() { } and let the compiler interpret it as: int foobar2(alias f) if ("the correct constraint which I don't want to learn how to write because the above SHOULD work") { } ?

Because that would be unlike everything else in D. Andrei

What do you mean? It's not unlike everything else in D. It's *exactly* like a function call in D.

No function definition expands into a template. =20 Andrei

Don't you all find it annoying to constantly keep whole threads, most of wh= ich are to your answer irrelevant, just to reply a few word?. Please instea= d keep only relevant snippet(s). Here the kept text is about 5kb. Denis -- -- -- -- -- -- -- vit esse estrany =E2=98=A3 spir.wikidot.com
Dec 19 2010
prev sibling next sibling parent spir <denis.spir gmail.com> writes:
On Sun, 19 Dec 2010 14:14:08 -0500
"Nick Sabalausky" <a a.a> wrote:

Don't you all find it annoying to constantly keep whole threads, most of=


which are to your answer irrelevant, just to reply a few word?. Please=20
instead keep only relevant snippet(s). Here the kept text is about 5kb. =


=20
 Scrolling is very, very easy, and 5k is tiny.=20

Scrolling pages and pages of useless text on every message just to find a f= ew words: is no fun. 5kb * thousands of subscribers * thousands of messages= /month * thousands of mailing lists: makes some weight. Anyway... (hears who is willing to hear) Denis -- -- -- -- -- -- -- vit esse estrany =E2=98=A3 spir.wikidot.com
Dec 19 2010
prev sibling next sibling parent Daniel Gibson <metalcaedes gmail.com> writes:
On Sun, Dec 19, 2010 at 5:44 PM, Andrei Alexandrescu
<SeeWebsiteForEmail erdani.org> wrote:
 On 12/19/10 10:35 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:
 On 12/19/10 9:32 AM, Ary Borenszweig wrote:
 I have this code:

 ---
 import std.stdio;

 int foobar(int delegate(int) f) {
 return f(1);
 }

 int foobar2(string s)() {
 int x =3D 1;
 mixin("return " ~ s ~ ";");
 }

 void main() {
 writefln("%d", foobar((int x) { return 2*x; }));
 writefln("%d", foobar2!("9876*x"));
 }
 ---

 When I compile it with -O -inline I can see with obj2asm that for the
 first writefln the delegate is being called. However, for the second
 it just passes
 9876 to writefln.

 From this I can say many things:
 - It seems that if I want hyper-high performance in my code I must use
 string mixins because delegate calls, even if they are very simple and
 the
 functions that uses them are also very simple, are not inlined. This
 has the drawback that each call to foobar2 with a different string
 will generate a
 different method in the object file.

You forgot: writefln("%d", foobar2!((x) { return 2*x; })()); That's a real delegate, not a string, but it will be inlined. Andrei

Sorry, I don't understand. I tried these: 1. int foobar3(int delegate(int) f)() { return f(1); } writefln("%d", foobar3!((int x) { return 2*x; })()); =3D> foo.d(12): Error: arithmetic/string type expected for value-parameter, not int delegate(int) 2. int foobar3()(int delegate(int) f) { return f(1); } writefln("%d", foobar3!()((int x) { return 2*x; })); =3D> Works, but it doesn't get inlined. And I tried that "(x) { ... }" syntax and it doesn't work. Sorry, it must be my fault I'm doing something wrong. What's the correct way of writing optimized code in D, code that I'm sure the compiler will know how to optimize?

void foobar3(alias fun)() { =A0 =A0return fun(1); } Andrei

I think using an alias makes the code less readable. "int foobar(int delegate(int) f)" tells you that the argument should be (a delegate of) a function that accepts an int and returns an int. "foobar3(alias fun)()" tells you almost nothing. You know that some kind of template parameter is expected, but not if it's a function or whatever, and even less what signature that function should have. IMHO some other syntax than just "alias fun" should be used for this purpos= e (inlined delegates known at compile time) - some syntax that documents the signature of the expected function, like with real delegates. Cheers, - Daniel
Dec 19 2010
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
There's an isDelegate template function in std.traits, but I think
there's some kind of bug there. I've reported it and I'm waiting for
answers.

Otherwise there are other functions you can use, e.g.:

isSomeFunction(T), isCallable(T), is(FunctionTypeOf(T) == delegate)..

On 12/19/10, Michel Fortin <michel.fortin michelf.com> wrote:
 On 2010-12-19 15:30:50 -0500, Ary Borenszweig <ary esperanto.org.ar> said:

 But that is a template:

 int foobar2(int delegate(int x) f)() {
 }

 It's a template that doesn't work because I have to write it in a
 different way. Sorry, I tried many different template constraints and
 none of them work.

 I tried these:

 int foobar2(alias f)()
    if (typeof(f) == typeid(int delegate(int x)))
    if (is(typeof(f) == int delegate(int)))
    if (is(typeof(f) == delegate))

 What do I have to write to make it work?

int foobar2(alias f)() if (is(typeof(f(int.init)) == int)) On the plus side, it'll not only work with delegates but also with regular functions, template functions, and objects with an opCall member. If you absolutely want to limit it to a delegate, you can try this: int foobar2(alias f)() if (is(typeof(&f) == int delegate(int))) -- Michel Fortin michel.fortin michelf.com http://michelf.com/

Dec 19 2010
prev sibling parent Daniel Gibson <metalcaedes gmail.com> writes:
On Mon, Dec 20, 2010 at 1:06 AM, loser <noneedtotalkanymore to.me> wrote:
 Daniel Gibson Wrote:

 On Sun, Dec 19, 2010 at 5:44 PM, Andrei Alexandrescu
 <SeeWebsiteForEmail erdani.org> wrote:
 On 12/19/10 10:35 AM, Ary Borenszweig wrote:
 On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:
 On 12/19/10 9:32 AM, Ary Borenszweig wrote:
 I have this code:

 ---
 import std.stdio;

 int foobar(int delegate(int) f) {
 return f(1);
 }

 int foobar2(string s)() {
 int x =3D 1;
 mixin("return " ~ s ~ ";");
 }

 void main() {
 writefln("%d", foobar((int x) { return 2*x; }));
 writefln("%d", foobar2!("9876*x"));
 }
 ---

 When I compile it with -O -inline I can see with obj2asm that for t=






 first writefln the delegate is being called. However, for the secon=






 it just passes
 9876 to writefln.

 From this I can say many things:
 - It seems that if I want hyper-high performance in my code I must =






 string mixins because delegate calls, even if they are very simple =






 the
 functions that uses them are also very simple, are not inlined. Thi=






 has the drawback that each call to foobar2 with a different string
 will generate a
 different method in the object file.

You forgot: writefln("%d", foobar2!((x) { return 2*x; })()); That's a real delegate, not a string, but it will be inlined. Andrei

Sorry, I don't understand. I tried these: 1. int foobar3(int delegate(int) f)() { return f(1); } writefln("%d", foobar3!((int x) { return 2*x; })()); =3D> foo.d(12): Error: arithmetic/string type expected for value-parameter, not int delegate(int) 2. int foobar3()(int delegate(int) f) { return f(1); } writefln("%d", foobar3!()((int x) { return 2*x; })); =3D> Works, but it doesn't get inlined. And I tried that "(x) { ... }" syntax and it doesn't work. Sorry, it must be my fault I'm doing something wrong. What's the corr=




 way of writing optimized code in D, code that I'm sure the compiler w=




 know how to optimize?

void foobar3(alias fun)() { =A0 =A0return fun(1); } Andrei

I think using an alias makes the code less readable. "int foobar(int delegate(int) f)" tells you that the argument should be =


 delegate of) a function that accepts an int and returns an int.
 "foobar3(alias fun)()" tells you almost nothing. You know that some kind=


 template parameter is expected, but not if it's a function or whatever, =


 even less what signature that function should have.

 IMHO some other syntax than just "alias fun" should be used for this pur=


 (inlined delegates known at compile time) - some syntax that documents t=


 =A0signature of the expected function, like with real delegates.

Hear, hear. Another problem with this approach I couldn't even think of. =

ent the domain of the comparator/predicate.

I don't think illegal code would compile, when fun is called in foobar() th= e compiler will check if the function aliased by fun has a suitable signature= . My point concerns only readability of function-signatures, I think. IMHO when you look at a function signature you should know what kind of parameters are expected, at least in a strongly typed language.
Dec 19 2010