digitalmars.D - Optimizing delegates
- Ary Borenszweig (73/73) Dec 19 2010 I have this code:
- Jacob Carlborg (4/77) Dec 19 2010 I completely agree with this post.
- Andrei Alexandrescu (5/26) Dec 19 2010 You forgot:
- Ary Borenszweig (19/57) Dec 19 2010 Sorry, I don't understand. I tried these:
- Andrei Alexandrescu (5/67) Dec 19 2010 void foobar3(alias fun)() {
- Ary Borenszweig (35/111) Dec 19 2010 foo.d
- Ary Borenszweig (3/117) Dec 19 2010 Oops, sorry, it does get inlined, my mistake. I will submit a patch to
- Nick Sabalausky (10/124) Dec 19 2010 It's not completely useless: "int foobar(int delegate(int) f) { }" allow...
- Andrei Alexandrescu (3/9) Dec 19 2010 In fact you can select the alias at runtime, which is quite a trick.
- Ary Borenszweig (24/100) Dec 19 2010 This of course has the following problem:
- Andrei Alexandrescu (8/111) Dec 19 2010 Template constraints are meant to assuage that problem.
- Andrei Alexandrescu (7/12) Dec 19 2010 Let me add that good Lisp programmers understand that very well.
- Ary Borenszweig (12/136) Dec 19 2010 I understand.
- Andrei Alexandrescu (3/144) Dec 19 2010 Because that would be unlike everything else in D.
- Ary Borenszweig (3/157) Dec 19 2010 What do you mean? It's not unlike everything else in D. It's *exactly*
- Andrei Alexandrescu (3/165) Dec 19 2010 No function definition expands into a template.
- spir (16/184) Dec 19 2010 or
- Nick Sabalausky (3/6) Dec 19 2010 Scrolling is very, very easy, and 5k is tiny.
- spir (12/17) Dec 19 2010 =20
- Ary Borenszweig (13/182) Dec 19 2010 But that is a template:
- Michel Fortin (13/30) Dec 19 2010 int foobar2(alias f)()
- Andrej Mitrovic (6/36) Dec 19 2010 There's an isDelegate template function in std.traits, but I think
- Ary Borenszweig (20/62) Dec 19 2010 What I don't like about that is that it's not consistent. I can write:
- Daniel Gibson (14/93) Dec 19 2010 I think using an alias makes the code less readable.
- loser (2/98) Dec 19 2010 Hear, hear. Another problem with this approach I couldn't even think of....
- Daniel Gibson (22/120) Dec 19 2010 d
- Max Samukha (7/59) Dec 19 2010 int foobar3(alias f)() {
- loser (3/15) Dec 19 2010 It's only complex if you're an incompetent compiler writer. I knew whole...
- Walter Bright (2/3) Dec 31 2010 I can confirm that it is complex.
- so (4/7) Jan 01 2011 lol
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
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
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
On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:On 12/19/10 9:32 AM, Ary Borenszweig wrote: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?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
On 12/19/10 10:35 AM, Ary Borenszweig wrote:On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:void foobar3(alias fun)() { return fun(1); } AndreiOn 12/19/10 9:32 AM, Ary Borenszweig wrote: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?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
On 12/19/2010 01:44 PM, Andrei Alexandrescu wrote:On 12/19/10 10:35 AM, Ary Borenszweig wrote: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.On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:void foobar3(alias fun)() { return fun(1); } AndreiOn 12/19/10 9:32 AM, Ary Borenszweig wrote: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?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
On 12/19/2010 01:57 PM, Ary Borenszweig wrote:On 12/19/2010 01:44 PM, Andrei Alexandrescu wrote:Oops, sorry, it does get inlined, my mistake. I will submit a patch to DMD right now with the above error.On 12/19/10 10:35 AM, Ary Borenszweig wrote: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.On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:void foobar3(alias fun)() { return fun(1); } AndreiOn 12/19/10 9:32 AM, Ary Borenszweig wrote: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?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
"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: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)()". :)On 12/19/10 10:35 AM, Ary Borenszweig wrote: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.On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:void foobar3(alias fun)() { return fun(1); } AndreiOn 12/19/10 9:32 AM, Ary Borenszweig wrote: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?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
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
On 12/19/2010 01:44 PM, Andrei Alexandrescu wrote:On 12/19/10 10:35 AM, Ary Borenszweig wrote: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".On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:void foobar3(alias fun)() { return fun(1); } AndreiOn 12/19/10 9:32 AM, Ary Borenszweig wrote: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?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
On 12/19/10 11:13 AM, Ary Borenszweig wrote:On 12/19/2010 01:44 PM, Andrei Alexandrescu wrote: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. AndreiOn 12/19/10 10:35 AM, Ary Borenszweig wrote: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".On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:void foobar3(alias fun)() { return fun(1); } AndreiOn 12/19/10 9:32 AM, Ary Borenszweig wrote: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?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
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
On 12/19/2010 02:17 PM, Andrei Alexandrescu wrote:On 12/19/10 11:13 AM, Ary Borenszweig wrote: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") { } ?On 12/19/2010 01:44 PM, Andrei Alexandrescu wrote: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. AndreiOn 12/19/10 10:35 AM, Ary Borenszweig wrote: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".On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:void foobar3(alias fun)() { return fun(1); } AndreiOn 12/19/10 9:32 AM, Ary Borenszweig wrote: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?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
On 12/19/10 11:23 AM, Ary Borenszweig wrote:On 12/19/2010 02:17 PM, Andrei Alexandrescu wrote:Because that would be unlike everything else in D. AndreiOn 12/19/10 11:13 AM, Ary Borenszweig wrote: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") { } ?On 12/19/2010 01:44 PM, Andrei Alexandrescu wrote: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. AndreiOn 12/19/10 10:35 AM, Ary Borenszweig wrote: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".On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:void foobar3(alias fun)() { return fun(1); } AndreiOn 12/19/10 9:32 AM, Ary Borenszweig wrote: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?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
On 12/19/2010 02:28 PM, Andrei Alexandrescu wrote:On 12/19/10 11:23 AM, Ary Borenszweig wrote:What do you mean? It's not unlike everything else in D. It's *exactly* like a function call in D.On 12/19/2010 02:17 PM, Andrei Alexandrescu wrote:Because that would be unlike everything else in D. AndreiOn 12/19/10 11:13 AM, Ary Borenszweig wrote: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") { } ?On 12/19/2010 01:44 PM, Andrei Alexandrescu wrote: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. AndreiOn 12/19/10 10:35 AM, Ary Borenszweig wrote: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".On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:void foobar3(alias fun)() { return fun(1); } AndreiOn 12/19/10 9:32 AM, Ary Borenszweig wrote: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?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
On 12/19/10 11:35 AM, Ary Borenszweig wrote:On 12/19/2010 02:28 PM, Andrei Alexandrescu wrote:No function definition expands into a template. AndreiOn 12/19/10 11:23 AM, Ary Borenszweig wrote:What do you mean? It's not unlike everything else in D. It's *exactly* like a function call in D.On 12/19/2010 02:17 PM, Andrei Alexandrescu wrote:Because that would be unlike everything else in D. AndreiOn 12/19/10 11:13 AM, Ary Borenszweig wrote: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") { } ?On 12/19/2010 01:44 PM, Andrei Alexandrescu wrote: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. AndreiOn 12/19/10 10:35 AM, Ary Borenszweig wrote: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".On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:void foobar3(alias fun)() { return fun(1); } AndreiOn 12/19/10 9:32 AM, Ary Borenszweig wrote: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?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
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:orOn 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=ustthe 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=pleuse string mixins because delegate calls, even if they are very sim=ingand 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=erSorry, 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 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. AndreiorThis 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), =will know how to optimize?void foobar3(alias fun)() { return fun(1); } Andrei'totherwise 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=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=20 No function definition expands into a template. =20 AndreiWhat do you mean? It's not unlike everything else in D. It's *exactly* like a function call in D.Because that would be unlike everything else in D. AndreiI 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") { } ?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
"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
On Sun, 19 Dec 2010 14:14:08 -0500 "Nick Sabalausky" <a a.a> wrote:=20Don't you all find it annoying to constantly keep whole threads, most of==20which 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.=20Scrolling 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
On 12/19/2010 03:43 PM, Andrei Alexandrescu wrote:On 12/19/10 11:35 AM, Ary Borenszweig wrote: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?On 12/19/2010 02:28 PM, Andrei Alexandrescu wrote:No function definition expands into a template. AndreiOn 12/19/10 11:23 AM, Ary Borenszweig wrote:What do you mean? It's not unlike everything else in D. It's *exactly* like a function call in D.On 12/19/2010 02:17 PM, Andrei Alexandrescu wrote:Because that would be unlike everything else in D. AndreiOn 12/19/10 11:13 AM, Ary Borenszweig wrote: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") { } ?On 12/19/2010 01:44 PM, Andrei Alexandrescu wrote: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. AndreiOn 12/19/10 10:35 AM, Ary Borenszweig wrote: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".On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:void foobar3(alias fun)() { return fun(1); } AndreiOn 12/19/10 9:32 AM, Ary Borenszweig wrote: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?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
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
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
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: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.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
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: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, - DanielOn 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:void foobar3(alias fun)() { =A0 =A0return fun(1); } AndreiOn 12/19/10 9:32 AM, Ary Borenszweig wrote: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?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
Dec 19 2010
Daniel Gibson Wrote:On Sun, Dec 19, 2010 at 5:44 PM, Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> wrote: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.On 12/19/10 10:35 AM, Ary Borenszweig wrote: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.On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote:void foobar3(alias fun)() { return fun(1); } AndreiOn 12/19/10 9:32 AM, Ary Borenszweig wrote: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?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
On Mon, Dec 20, 2010 at 1:06 AM, loser <noneedtotalkanymore to.me> wrote:Daniel Gibson Wrote:heOn 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=dfirst writefln the delegate is being called. However, for the secon=useit 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 =andstring mixins because delegate calls, even if they are very simple =sthe functions that uses them are also very simple, are not inlined. Thi=ectSorry, 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=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. Andreiillway of writing optimized code in D, code that I'm sure the compiler w=(aI think using an alias makes the code less readable. "int foobar(int delegate(int) f)" tells you that the argument should be =know how to optimize?void foobar3(alias fun)() { =A0 =A0return fun(1); } Andreiofdelegate of) a function that accepts an int and returns an int. "foobar3(alias fun)()" tells you almost nothing. You know that some kind=andtemplate parameter is expected, but not if it's a function or whatever, =poseeven less what signature that function should have. IMHO some other syntax than just "alias fun" should be used for this pur=he(inlined delegates known at compile time) - some syntax that documents t=With luck, illegal code may compile. You have no clean way to enforce/docum= ent the domain of the comparator/predicate.=A0signature of the expected function, like with real delegates.Hear, hear. Another problem with this approach I couldn't even think of. =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
On 12/19/2010 06:35 PM, Ary Borenszweig wrote:On 12/19/2010 01:21 PM, Andrei Alexandrescu wrote: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.On 12/19/10 9:32 AM, Ary Borenszweig wrote: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)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
Andrei Alexandrescu Wrote:On 12/19/10 11:17 AM, Andrei Alexandrescu wrote:It's only complex if you're an incompetent compiler writer. I knew whole the time the main reason was someone's incompetence. You needed two posts to defend W. Poor man. I can't guess how extensively you've tested modern implementations of functional languages lately, but it's possible that some Lisp implementations don't inline small lambdas in cases like this. In general, passing small lambdas is as common in functional programming as semicolons in D. Would be strange if they didn't optimize them well nowadays.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).
Dec 19 2010
loser wrote:It's only complex if you're an incompetent compiler writer.I can confirm that it is complex.
Dec 31 2010
lol (Sorry couldn't resist!) On Sat, 01 Jan 2011 04:00:37 +0200, Walter Bright <newshound2 digitalmars.com> wrote:loser wrote:It's only complex if you're an incompetent compiler writer.I can confirm that it is complex.
Jan 01 2011