Thread overview
Structs, Speed and refs.
Oct 23, 2012
Jakob Bornecrantz
Oct 23, 2012
Daniel Kozák
Oct 23, 2012
Jakob Bornecrantz
Oct 23, 2012
martin
October 23, 2012
Hey everybody!

A bit of background; I'm porting some code over from D1 to D2 and I ran into a bit of a problem. I have a bunch of code that looks something like this:

class Bar : Other {
  override void func(ref LargeStruct st) {}
}

Bar bar;
LargeStruct foo, too;
bar.func(foo - too);

This compiles just fine in D1 but no longer in D2. Because the temp created by "foo - too" is not a lvalue apparently. I don't want to remove the "ref" storage type because i still want it to be fast. And I rather have neater looking code vs:

LargeStruct foo, too, temp;
temp = foo - too;
bar.func(temp);

One solution is to turn "in" structs into pass by reference, eg const ref, but not require lvalue semantics at the call site?

Cheers, Jakob.
October 23, 2012
Hi,

First of all, I think there is no difference in speed between

LargeStruct foo, too, temp;
temp = foo - too;
bar.func(temp);

and with func without ref.

How looks your opBinary(Right) method?

For eg. this works for me:

struct LargeStruct {
	int x;
	
	auto ref opBinary(string op)(LargeStruct rhs) if (op == "-") {		
		this.x = this.x - rhs.x;
		return this;
	}
}

class Bar {
  void func(ref LargeStruct st) {}
}


void main(string[] args)
{
	Bar bar = new Bar();
	LargeStruct foo, too;
	bar.func(foo - too);
}

However this will modify foo struct.


On Tuesday, 23 October 2012 at 09:44:06 UTC, Jakob Bornecrantz wrote:
> Hey everybody!
>
> A bit of background; I'm porting some code over from D1 to D2 and I ran into a bit of a problem. I have a bunch of code that looks something like this:
>
> class Bar : Other {
>   override void func(ref LargeStruct st) {}
> }
>
> Bar bar;
> LargeStruct foo, too;
> bar.func(foo - too);
>
> This compiles just fine in D1 but no longer in D2. Because the temp created by "foo - too" is not a lvalue apparently. I don't want to remove the "ref" storage type because i still want it to be fast. And I rather have neater looking code vs:
>
> LargeStruct foo, too, temp;
> temp = foo - too;
> bar.func(temp);
>
> One solution is to turn "in" structs into pass by reference, eg const ref, but not require lvalue semantics at the call site?
>
> Cheers, Jakob.


October 23, 2012
On Tuesday, 23 October 2012 at 10:36:11 UTC, Daniel Kozák wrote:
> Hi,
>
> First of all, I think there is no difference in speed between
>
> LargeStruct foo, too, temp;
> temp = foo - too;
> bar.func(temp);
>
> and with func without ref.

That doesn't seem to be the case, as at least DMD always copies
to the stack. Even if I change the function to have the struct
as a unused local variable it still copies.

void example(LargeStruct t, Bar bar)
{
   bar.func(t);
}

with ref:
Dump of assembler code for function _D7example4testFS7example11LargeStructC7example3BarZv:
   0x0000000000425ee0 <+0>:	push   %rbp
   0x0000000000425ee1 <+1>:	mov    %rsp,%rbp
   0x0000000000425ee4 <+4>:	sub    $0x10,%rsp
   0x0000000000425ee8 <+8>:	lea    0x10(%rbp),%rsi
   0x0000000000425eec <+12>:	mov    (%rdi),%rax
   0x0000000000425eef <+15>:	rex.W callq *0x30(%rax)
   0x0000000000425ef3 <+19>:	mov    %rbp,%rsp
   0x0000000000425ef6 <+22>:	pop    %rbp
   0x0000000000425ef7 <+23>:	retq

without ref:
Dump of assembler code for function _D7example4testFS7example11LargeStructC7example3BarZv:
   0x0000000000425ee0 <+0>:	push   %rbp
   0x0000000000425ee1 <+1>:	mov    %rsp,%rbp
   0x0000000000425ee4 <+4>:	sub    $0x10,%rsp
   0x0000000000425ee8 <+8>:	lea    0x208(%rbp),%rsi
   0x0000000000425eef <+15>:	mov    $0x40,%ecx
   0x0000000000425ef4 <+20>:	pushq  (%rsi)
   0x0000000000425ef6 <+22>:	sub    $0x8,%rsi
   0x0000000000425efa <+26>:	loop   0x425ef4 <_D7example4testFS7example11LargeStructC7example3BarZv+20>
   0x0000000000425efc <+28>:	mov    (%rdi),%rax
   0x0000000000425eff <+31>:	rex.W callq *0x30(%rax)
   0x0000000000425f03 <+35>:	add    $0x200,%rsp
   0x0000000000425f0a <+42>:	mov    %rbp,%rsp
   0x0000000000425f0d <+45>:	pop    %rbp
   0x0000000000425f0e <+46>:	retq


>
> How looks your opBinary(Right) method?
>
> For eg. this works for me:
>
> struct LargeStruct {
> 	int x;
> 	
> 	auto ref opBinary(string op)(LargeStruct rhs) if (op == "-") {		
> 		this.x = this.x - rhs.x;
> 		return this;
> 	}
> }
>
> class Bar {
>   void func(ref LargeStruct st) {}
> }
>
>
> void main(string[] args)
> {
> 	Bar bar = new Bar();
> 	LargeStruct foo, too;
> 	bar.func(foo - too);
> }
>
> However this will modify foo struct.

Since this is D1 code being ported I'm currently using
opSub. I tried changing your code to opSub and I got the
same error as with mine. Your example should probably be
an error. I'm not saying I was right in doing what I did.
The point of the post was to improve D.

Cheers, Jakob.


October 23, 2012
On Tuesday, 23 October 2012 at 09:44:06 UTC, Jakob Bornecrantz wrote:
> One solution is to turn "in" structs into pass by reference, eg const ref, but not require lvalue semantics at the call site?

And here we go again - missing rvalue-to-const-ref propagation. Check out http://forum.dlang.org/thread/yhnbcocwxnbutylfeoxi@forum.dlang.org