Re: Should we add `a * b` for vectors?

2017-10-03 Thread Enamex via Digitalmars-d
On Thursday, 28 September 2017 at 01:58:24 UTC, Walter Bright 
wrote:

On 9/27/2017 4:21 PM, Manu wrote:
[...]
but I see no advantage to it over D's approach (the reverse 
operand lookup scheme).


I couldn't find anything focused on D's overloading resolution 
scheme (or anything with the specific term "reverse operand 
lookup"). Can you elaborate?


Just playing with compiler explorer to see assembly line count.

2017-10-03 Thread SrMordred via Digitalmars-d

//D compiled with gdc 5.2 -O3

auto test(int[] arr, int cmp)
{
int[] r;
foreach(v ; arr)
if(v == cmp)r~=v;
return r;
}
// 51 lines of assembly

auto test(int[] arr, int cmp)
{
  return arr.filter!((v)=>v==cmp).array;
}
//1450 lines... what?

Ok let me look also at c++:
//gcc 7.2 -O3

vector test(vector& arr, int cmp) {
vector r;
for(auto v : arr)
if(v == cmp)r.push_back(v);
return r;
}
//152 lines. more than D :)

vector test(vector& arr, int cmp) {
vector r;
std::copy_if (arr.begin(), arr.end(), std::back_inserter(r),
 [cmp](int i){return i==cmp;} );
return r;
}

//150 lines. That what i expected earlier with D.

Hmm. let me be 'fair' and use std.container.array just for 
curiosity:


auto test(ref Array!int arr, int cmp)
{
Array!int r;
foreach(v ; arr)
if(v == cmp)r.insert(v);
return r;
}

//5542 lines... what??

Someone interested to discuss about this?

Or point me some grotesque mistake.


Re: Just playing with compiler explorer to see assembly line count.

2017-10-03 Thread rikki cattermole via Digitalmars-d
Be warned, x86 cpu's today are not like they were 10 years ago. A good 
portion of a symbol could be full of nop's and it could end up being 
faster than the one without them.


Next, compare against ldc, not gdc primarily. Its better maintained and 
ugh more inline with dmd (its a bit of a mess, lets not go there). Of 
course nothing wrong with doing both.


std.container.* is basically dead. We need to replace it. We are 
currently waiting on std.experimental.allocators before going much more 
further (also a lot of other no-gc stuff).


Compare (on https://d.godbolt.org/ with "ldc -O3" and "gdc -O3"):
---
auto test1(int[] arr, int cmp)
{
int[] r;
foreach(v ; arr)
  if(v == cmp)r~=v;
return r;
}

import std.container.array;
auto test2(ref Array!int arr, int cmp)
{
Array!int r;
foreach(v ; arr)
  if(v == cmp)r.insert(v);
return r;
}
---


Re: Just playing with compiler explorer to see assembly line count.

2017-10-03 Thread SrMordred via Digitalmars-d
On Tuesday, 3 October 2017 at 13:53:38 UTC, rikki cattermole 
wrote:
Be warned, x86 cpu's today are not like they were 10 years ago. 
A good portion of a symbol could be full of nop's and it could 
end up being faster than the one without them.


Next, compare against ldc, not gdc primarily. Its better 
maintained and ugh more inline with dmd (its a bit of a mess, 
lets not go there). Of course nothing wrong with doing both.


std.container.* is basically dead. We need to replace it. We 
are currently waiting on std.experimental.allocators before 
going much more further (also a lot of other no-gc stuff).


Compare (on https://d.godbolt.org/ with "ldc -O3" and "gdc 
-O3"):

---
auto test1(int[] arr, int cmp)
{
int[] r;
foreach(v ; arr)
  if(v == cmp)r~=v;
return r;
}

import std.container.array;
auto test2(ref Array!int arr, int cmp)
{
Array!int r;
foreach(v ; arr)
  if(v == cmp)r.insert(v);
return r;
}
---

With ldc the results are similar.
5k+
And I know, im not into performance comparison yet. But you know, 
less code, more cache friendly (and sometimes better performance).


But my big surprise was with .filter.





Re: Just playing with compiler explorer to see assembly line count.

2017-10-03 Thread Iain Buclaw via Digitalmars-d

On Tuesday, 3 October 2017 at 14:07:39 UTC, SrMordred wrote:
On Tuesday, 3 October 2017 at 13:53:38 UTC, rikki cattermole 
wrote:
Be warned, x86 cpu's today are not like they were 10 years 
ago. A good portion of a symbol could be full of nop's and it 
could end up being faster than the one without them.


Next, compare against ldc, not gdc primarily. Its better 
maintained and ugh more inline with dmd (its a bit of a mess, 
lets not go there). Of course nothing wrong with doing both.


std.container.* is basically dead. We need to replace it. We 
are currently waiting on std.experimental.allocators before 
going much more further (also a lot of other no-gc stuff).


Compare (on https://d.godbolt.org/ with "ldc -O3" and "gdc 
-O3"):

---
auto test1(int[] arr, int cmp)
{
int[] r;
foreach(v ; arr)
  if(v == cmp)r~=v;
return r;
}

import std.container.array;
auto test2(ref Array!int arr, int cmp)
{
Array!int r;
foreach(v ; arr)
  if(v == cmp)r.insert(v);
return r;
}
---

With ldc the results are similar.
5k+
And I know, im not into performance comparison yet. But you 
know, less code, more cache friendly (and sometimes better 
performance).




Well -O3 does not generate cache friendly assembly anyway. For 
instance, inlining functions regardless of cost.


I'd take the assembly count with a pinch of salt when you are 
using templated code.


Iain




Re: Alternatives to extern(delegate) (DIP 1011)

2017-10-03 Thread Jonathan Marler via Digitalmars-d

On Monday, 2 October 2017 at 07:48:54 UTC, Jonathan Marler wrote:
Andrei suggests we take a closer look at alternatives to DIP 
1011 (extern(delegate)) that can be implemented in a library.  
In the past I've failed to come up with anything good, however, 
my last attempt seemed to be less horrible than before.  I'm 
inviting anyone to view/modify my feeble attempt at a solution 
here https://github.com/marler8997/externdelegate


A good library solution would be great but my current solution 
has problems.  It doesn't really support template parameters 
yet and I'm not sure if it can be solved in the general case 
without pulling in a fair chunk of the language grammar into 
the library. Assuming that can be fixed, the bigger concern is 
that the API to define a "delegate function" looks very 
awkward.  It provides a template mixin that you can use to 
create a delegate function by passing in your function 
definition as a string.


With the current solution I believe its very unlikely that 
applications would use the library. Keep in mind that this 
feature is something that a library could use on most or all of 
it's functions.  If it has to use such an awkward syntax it's 
highly unlikely it would be used at that scale.  Not to mention 
that when you start pushing the limits of the language like 
this you almost always run into bugs and end up having to go 
with a different solution.  Also I haven't measured it but I'm 
almost certain this would greatly increase compile time as more 
functions start using it.


I've improved the solution.  I've gotten templates to work, 
however, template parameter deduction won't work because I'm 
currently defining the delegate functions as structs.  I'm 
including a bit of code to demonstrate the solution.  The example 
will demonstrate how to define a "delegate function" that uses a 
File object for it's context.  The function is called 
"importantWriteln" which simply calls writeln with a prefix of 
"Important: ".  Here's how you would define that function:


mixin delegateFunctionImpl!("importantWriteln", "(T...)", 
"File", "file", "T args",

q{
file.writeln("Important: ", args);
});

This is the code that the mixin would generate:

struct importantWriteln(T...)
{
File file;
auto opCall(T args)
{
file.writeln("Important: ", args);
}
pragma(inline) static auto opCall(ref File file, T args)
{
return (cast(importantWriteln*)&file).opCall(args);
}
// NOTE: this doesn't quite work yet if there are 
template parameters
pragma(inline) static auto createDelegate(T...)(ref File 
file)

{
return &(cast(importantWriteln*)&file).opCall;
}
}

And here's how you would use it:

// call like a normal function
importantWriteln!(string,string)(stdout, "Hello, ", "World!");
// NOTE: template type deduction doesn't work since 
importantWriteln is a struct


// call like a delegate
auto dg = 
importantWriteln!(string,string).createDelegate(stdout);

dg("Hello, ", "again");

The worst part about this solution is how you define the 
function.  The way I evaluate the solution is I think about ALL 
the functions in phobos that could use this feature (most 
functions that would normally be called using UFCS are good 
candidates) then think about whether I could create a pull 
request to make them all delegate functions.  Given this 
solution, I don't think that it would be accepted.


Re: Just playing with compiler explorer to see assembly line count.

2017-10-03 Thread Daniel Kozak via Digitalmars-d
is not bad

https://godbolt.org/g/bSfubs

On Tue, Oct 3, 2017 at 3:19 PM, SrMordred via Digitalmars-d <
digitalmars-d@puremagic.com> wrote:

> //D compiled with gdc 5.2 -O3
>
> auto test(int[] arr, int cmp)
> {
> int[] r;
> foreach(v ; arr)
> if(v == cmp)r~=v;
> return r;
> }
> // 51 lines of assembly
>
> auto test(int[] arr, int cmp)
> {
>   return arr.filter!((v)=>v==cmp).array;
> }
> //1450 lines... what?
>
> Ok let me look also at c++:
> //gcc 7.2 -O3
>
> vector test(vector& arr, int cmp) {
> vector r;
> for(auto v : arr)
> if(v == cmp)r.push_back(v);
> return r;
> }
> //152 lines. more than D :)
>
> vector test(vector& arr, int cmp) {
> vector r;
> std::copy_if (arr.begin(), arr.end(), std::back_inserter(r),
>  [cmp](int i){return i==cmp;} );
> return r;
> }
>
> //150 lines. That what i expected earlier with D.
>
> Hmm. let me be 'fair' and use std.container.array just for curiosity:
>
> auto test(ref Array!int arr, int cmp)
> {
> Array!int r;
> foreach(v ; arr)
> if(v == cmp)r.insert(v);
> return r;
> }
>
> //5542 lines... what??
>
> Someone interested to discuss about this?
>
> Or point me some grotesque mistake.
>


Re: Just playing with compiler explorer to see assembly line count.

2017-10-03 Thread SrMordred via Digitalmars-d

On Tuesday, 3 October 2017 at 17:15:04 UTC, Daniel Kozak wrote:

is not bad

https://godbolt.org/g/bSfubs


Thats cool, I never used copy xD.
(but you returned the .copy range, not the 'r' array ;p)

//now with ldc 1.4 and -O3 -release -boundscheck=off

foreach   -> 99 lines
.filter.copy  -> 368 lines
.filter.array -> 1229 lines (1002 lines with -O1)



Re: Should we add `a * b` for vectors?

2017-10-03 Thread Walter Bright via Digitalmars-d

On 10/2/2017 4:15 AM, Timon Gehr wrote:

On 30.09.2017 23:45, Walter Bright wrote:

...
D has other ways of doing what ADL does,


What are those ways? I'm aware of two basic strategies, both suboptimal:

- Every module imports all other modules.
- Proliferation of wrapper types.


https://dlang.org/spec/operatoroverloading.html#binary

C++ does not have this notion.



It's not per se related to operator overloading:


ADL was specifically intended to address operator overloading.



---
module a;
import std.range: isInputRange;
auto sum(R)(R r)if(isInputRange!R){
     typeof(r.front) result;
     for(auto t=r.save;!t.empty;t.popFront())
     result+=t.front;
     return result;
}
---

---
module b;
import a;
import std.range;

void main(){
     int[] a = [1,2,3,4];
     import std.stdio: writeln;
     writeln(a.front); // ok
     writeln(sum(a)); // error, the type is an input range, yet has no front
}
---

I.e., the operations that are supported on the type differ depending on the 
module that it is accessed from. If there are multiple definitions of the same 
name, different modules might not agree which one is being referred to. (This is 
particularly likely for overloaded operators, as the set of names is finite and 
small. This is what Manu means when he says it can lead to nasty surprises. This 
is very plausible, but I don't have a good example.)


This gets into the anti-hijacking support D has (and C++ does not). If multiple 
modules with declarations of `writeln` are in scope, the compiler attempts a 
match with `writeln` in each module. If there is a match with more than one 
module, an error is issued. The user will then have to specify which one he wants.


This is specifically designed to prevent nasty surprises. C++ has a big problem 
with ADL in that overloading is not encapsulated and any #included header can 
inadvertently add more overloads that may be entirely unrelated. Any .h can 
crack open any namespace and insert more overloads into it. It's completely 
unhygienic and uncontrollable.


As for the specific example you gave, I get:

a.d(3): Error: no property 'front' for type 'int[]'
a.d(4): Error: no property 'save' for type 'int[]'
b.d(8): Error: template instance a.sum!(int[]) error instantiating


Re: Should we add `a * b` for vectors?

2017-10-03 Thread Walter Bright via Digitalmars-d

On 10/3/2017 12:58 AM, Enamex wrote:
I couldn't find anything focused on D's overloading resolution scheme (or 
anything with the specific term "reverse operand lookup"). Can you elaborate?


See my reply to Timon.


Re: Should we add `a * b` for vectors?

2017-10-03 Thread jmh530 via Digitalmars-d

On Tuesday, 3 October 2017 at 19:25:32 UTC, Walter Bright wrote:


This gets into the anti-hijacking support D has (and C++ does 
not). If multiple modules with declarations of `writeln` are in 
scope, the compiler attempts a match with `writeln` in each 
module. If there is a match with more than one module, an error 
is issued. The user will then have to specify which one he 
wants.




Anti-hacking might make it tricky to have operators as 
free-standing functions, but I'm not sure it would be impossible. 
The solution for function overloading is fully qualified names. 
However, this does not make sense operator overloading. Mixing 
operator overloading and D's anti-hijacking, you would basically 
be prevented from having two overloaded versions of an operator. 
This means that if you want multiple versions of operators, you 
would not be able to have the operators as member functions and 
they would have to be free-standing functions, ideally in 
separate modules.


With respect to the earlier discussion of type wrappers, this can 
also be implemented with a template parameters that controls the 
operator-overloading of *, something like below.


struct Foo(bool mtimesOverload = false)
{
template opBinary(string op = "*")(Foo foo)
{
static if (mtimesOverload)
{
return mtimes(this, foo);
}
else
{
return times(this, foo);
}
}
}

So you could do a Matrix alias that has mtimesOverload=true.


Re: gdc is in

2017-10-03 Thread Joakim via Digitalmars-d

On Wednesday, 21 June 2017 at 15:11:39 UTC, Joakim wrote:

the gcc tree:

https://gcc.gnu.org/ml/gcc/2017-06/msg00111.html

Congratulations to Iain and the gdc team. :)

I found out because it's on the front page of HN right now, 
where commenters are asking questions about D.


An update, including the latest 2.076 frontend:

https://www.phoronix.com/scan.php?page=news_item&px=D-GCC-v3-Patches


Re: Should we add `a * b` for vectors?

2017-10-03 Thread Steven Schveighoffer via Digitalmars-d

On 10/3/17 3:25 PM, Walter Bright wrote:
This is specifically designed to prevent nasty surprises. C++ has a big 
problem with ADL in that overloading is not encapsulated and any 
#included header can inadvertently add more overloads that may be 
entirely unrelated. Any .h can crack open any namespace and insert more 
overloads into it. It's completely unhygienic and uncontrollable.


One thing I would like to have control over is how 'this' is passed.

A nice thing about UFCS is I can use it to pass-by-value the faux 'this' 
parameter, whereas I cannot do this with a member function. It makes a 
difference in some cases, especially with const functions.


It also can be cheaper to pass a small struct by value.

None of this is possible with operator overloading. A way out could 
possibly be to alias a non-member function for the operator.


-Steve


Re: Should we add `a * b` for vectors?

2017-10-03 Thread Walter Bright via Digitalmars-d

On 10/3/2017 5:24 PM, Steven Schveighoffer wrote:

It also can be cheaper to pass a small struct by value.


Should not be a problem if the compiler inlines it.


Re: gdc is in

2017-10-03 Thread Per Nordlöw via Digitalmars-d

On Tuesday, 3 October 2017 at 22:00:51 UTC, Joakim wrote:

On Wednesday, 21 June 2017 at 15:11:39 UTC, Joakim wrote:

the gcc tree:

https://gcc.gnu.org/ml/gcc/2017-06/msg00111.html

Congratulations to Iain and the gdc team. :)

I found out because it's on the front page of HN right now, 
where commenters are asking questions about D.


An update, including the latest 2.076 frontend:

https://www.phoronix.com/scan.php?page=news_item&px=D-GCC-v3-Patches


Does this include DMD and static if?


Re: gdc is in

2017-10-03 Thread Suliman via Digitalmars-d

On Tuesday, 3 October 2017 at 22:00:51 UTC, Joakim wrote:

On Wednesday, 21 June 2017 at 15:11:39 UTC, Joakim wrote:

the gcc tree:

https://gcc.gnu.org/ml/gcc/2017-06/msg00111.html

Congratulations to Iain and the gdc team. :)

I found out because it's on the front page of HN right now, 
where commenters are asking questions about D.


An update, including the latest 2.076 frontend:

https://www.phoronix.com/scan.php?page=news_item&px=D-GCC-v3-Patches


Cool, which version of GCC will have it?