Re: Optimizing delegates

2011-01-01 Thread so

lol

(Sorry couldn't resist!)

On Sat, 01 Jan 2011 04:00:37 +0200, Walter Bright  
 wrote:



loser wrote:

It's only complex if you're an incompetent compiler writer.


I can confirm that it is complex.


Re: Optimizing delegates

2010-12-31 Thread Walter Bright

loser wrote:

It's only complex if you're an incompetent compiler writer.


I can confirm that it is complex.


Re: Optimizing delegates

2010-12-19 Thread Andrei Alexandrescu

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


Re: Optimizing delegates

2010-12-19 Thread Daniel Gibson
On Mon, Dec 20, 2010 at 1:06 AM, loser  wrote:
> Daniel Gibson Wrote:
>
>> On Sun, Dec 19, 2010 at 5: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
>> >
>>
>> 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.
>

I don't think illegal code would compile, when fun is called in foobar() the
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.


Re: Optimizing delegates

2010-12-19 Thread loser
Daniel Gibson Wrote:

> On Sun, Dec 19, 2010 at 5: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
> >
> 
> 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.


Re: Optimizing delegates

2010-12-19 Thread loser
Andrei Alexandrescu Wrote:

> 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).

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.


Re: Optimizing delegates

2010-12-19 Thread Ary Borenszweig

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  wrote:

On 2010-12-19 15:30:50 -0500, Ary Borenszweig  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.for...@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.


Re: Optimizing delegates

2010-12-19 Thread Andrej Mitrovic
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  wrote:
> On 2010-12-19 15:30:50 -0500, Ary Borenszweig  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.for...@michelf.com
> http://michelf.com/
>
>


Re: Optimizing delegates

2010-12-19 Thread Michel Fortin

On 2010-12-19 15:30:50 -0500, Ary Borenszweig  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.for...@michelf.com
http://michelf.com/



Re: Optimizing delegates

2010-12-19 Thread Daniel Gibson
On Sun, Dec 19, 2010 at 5: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
>

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.

 Cheers,
 - Daniel


Re: Optimizing delegates

2010-12-19 Thread Ary Borenszweig

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?


Re: Optimizing delegates

2010-12-19 Thread spir
On Sun, 19 Dec 2010 14:14:08 -0500
"Nick Sabalausky"  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 
> >instead keep only relevant snippet(s). Here the kept text is about 5kb.  
> 
> Scrolling is very, very easy, and 5k is tiny. 

Scrolling pages and pages of useless text on every message just to find a few 
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 ☣

spir.wikidot.com



Re: Optimizing delegates

2010-12-19 Thread Nick Sabalausky
"spir"  wrote in message 
news:mailman.35.1292785009.4748.digitalmar...@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. 




Re: Optimizing delegates

2010-12-19 Thread Nick Sabalausky
"Ary Borenszweig"  wrote in message 
news:ieldl1$1of...@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; })());
> }
>
> aster...@deep-water:~/dmd2/linux/bin$ ./dmd foo.d -O -inline
> aster...@deep-water:~/dmd2/linux/bin$ ./obj2asm foo.o | vi -
> (line 530)
> _Dmain:
> push EBP
> mov EBP,ESP
> mov EAX,offset FLAT:_d3std5stdio6stdouts3std5stdio4f...@sym32
> push dword ptr _t...@sym32[0eh]
> push dword ptr _t...@sym32[010h]
> push 02694h
> call   _d3std5stdio4file19__t8writeflntayatiz8writeflnmfaya...@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)()".  :)




Re: Optimizing delegates

2010-12-19 Thread spir
On Sun, 19 Dec 2010 12:43:23 -0600
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(

Re: Optimizing delegates

2010-12-19 Thread Andrei Alexandrescu

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


Re: Optimizing delegates

2010-12-19 Thread Ary Borenszweig

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.


Re: Optimizing delegates

2010-12-19 Thread Andrei Alexandrescu

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


Re: Optimizing delegates

2010-12-19 Thread Andrei Alexandrescu

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


Re: Optimizing delegates

2010-12-19 Thread Ary Borenszweig

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") {

}

?


Re: Optimizing delegates

2010-12-19 Thread Andrei Alexandrescu

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


Re: Optimizing delegates

2010-12-19 Thread Ary Borenszweig

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".


Re: Optimizing delegates

2010-12-19 Thread Ary Borenszweig

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; })());
}

aster...@deep-water:~/dmd2/linux/bin$ ./dmd foo.d -O -inline
aster...@deep-water:~/dmd2/linux/bin$ ./obj2asm foo.o | vi -
(line 530)
_Dmain:
push EBP
mov EBP,ESP
mov EAX,offset FLAT:_d3std5stdio6stdouts3std5stdio4f...@sym32
push dword ptr _t...@sym32[0eh]
push dword ptr _t...@sym32[010h]
push 02694h
call _d3std5stdio4file19__t8writeflntayatiz8writeflnmfaya...@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.


Re: Optimizing delegates

2010-12-19 Thread Ary Borenszweig

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; })());
}

aster...@deep-water:~/dmd2/linux/bin$ ./dmd foo.d -O -inline
aster...@deep-water:~/dmd2/linux/bin$ ./obj2asm foo.o | vi -
(line 530)
_Dmain:
pushEBP
mov EBP,ESP
mov EAX,offset 
FLAT:_d3std5stdio6stdouts3std5stdio4f...@sym32
pushdword ptr _t...@sym32[0eh]
pushdword ptr _t...@sym32[010h]
push02694h
call  
_d3std5stdio4file19__t8writeflntayatiz8writeflnmfaya...@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.


Re: Optimizing delegates

2010-12-19 Thread Max Samukha

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.




Re: Optimizing delegates

2010-12-19 Thread Andrei Alexandrescu

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


Re: Optimizing delegates

2010-12-19 Thread Ary Borenszweig

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?


Re: Optimizing delegates

2010-12-19 Thread Andrei Alexandrescu

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


Re: Optimizing delegates

2010-12-19 Thread Jacob Carlborg

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


Optimizing delegates

2010-12-19 Thread Ary Borenszweig
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. :-(