www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - this(this) / opAssign

reply "Namespace" <rswhite4 googlemail.com> writes:
Is it expected behaviour that this code compiles and prints:

this(this)
this(this)

?
[code]
import std.stdio;

static if (!is(typeof(writeln)))
	alias writefln writeln;

struct vec2f {
public:
	float x, y;
	
	this(this) {
		writeln("this(this)");
	}
}

void main()
{
	vec2f v1 = vec2f(0, 1);
	vec2f v2 = vec2f(2, 3);
	
	v2 = v1;
	
	vec2f v3 = v2;
}
[/code]

while this code

[code]
import std.stdio;

static if (!is(typeof(writeln)))
	alias writefln writeln;

struct vec2f {
public:
	float x, y;
	
	this(this) {
		writeln("this(this)");
	}
	
	
	ref vec2f opAssign(ref const vec2f v) {
		writeln("opAssign");
		
		this.x = v.x;
		this.y = v.y;
		
		return this;
	}
}

void main()
{
	vec2f v1 = vec2f(0, 1);
	vec2f v2 = vec2f(2, 3);
	
	v2 = v1;
	
	vec2f v3 = v2;
}
[/code]

prints:

opAssign
this(this)
?

And what should I use, this(this) or opAssign? I thougth that it 
is unimportant,
but that changed my mind: http://dpaste.dzfl.pl/36ce3688
Jan 10 2013
next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 10 January 2013 at 23:03:30 UTC, Namespace wrote:
 And what should I use, this(this) or opAssign? I thougth that 
 it is unimportant,
 but that changed my mind: http://dpaste.dzfl.pl/36ce3688
The default generated opAssign will postblit the other struct over itself, then destroy it's own (old) body (if a postblit occured): import std.stdio; //---- struct S { this(this) { writeln("this(this)"); } ~this() { writeln("~this"); } } void main() { S a, b; writeln("Start"); a = b; writeln("Finish"); } //---- Produces //---- Start this(this) //Postblit a new copy ~this //Destroy the old body Finish ~this ~this //---- This is a very sweet deal: If you write a constructor (and optionally a destructor), then that's all you need for D to make things consistent. For example: //---- import std.stdio; struct S { int* p; this(int i) { p = new int; *p = i; } this(this) { int* p2 = new int; *p2 = *p; p = p2; } } void main() { S a = S(1); S b = S(2); writeln("Start"); a = b; assert(*a.p == 2); assert(a.p != b.p); writeln("Finish"); } //---- Here, the default generate opAssign is *not* "stupid" and will not straight up assign the pointers. After the assignments, each struct will still have their own personal payload! Now to answer your question: If your object is a POD, the no need for opAssign. If your object has a constructor, then the default opAssign should remain consistent with your construcor's behavior... ...BUT: you can still implement it yourself if (and only if) you need a custom behavior. In the above example, opAssign "worked", but it did needlessly re-alocate. This is the kind of situation where writing an opAssign is worth it.
Jan 10 2013
prev sibling next sibling parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Thursday, 10 January 2013 at 23:03:30 UTC, Namespace wrote:
 Is it expected behaviour that this code compiles and prints:
I think it is. Postblit 'this(this)' occurs while initializing a variable from one, rather than copying. Which you also can compare against move symantics. Correct me if i'm wrong. struct S { this(this) {writeln("this(this)"); } void opAssign(ref S s) {writeln("opAssign ref/copy");} void opAssign(S s) {writeln("opAssign move");} } //postblit S s1; S s2 = s1; //opAssign ref (copy) S s3; s3 = s1; //opAssign S (Move) S func() {return S();} s3 = func(); output: this(this) opAssign ref/copy opAssign move
Jan 10 2013
parent reply "Namespace" <rswhite4 googlemail.com> writes:
Without a declared opAssign, this

   S s3;
   s3 = s1;

also calls the postblit. That is strange.
Jan 10 2013
next sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 10 January 2013 at 23:37:14 UTC, Namespace wrote:
 Without a declared opAssign, this

   S s3;
   s3 = s1;

 also calls the postblit. That is strange.
If there is no user declared opAssign, then opAssign is implemented in terms of postblit. It's designed that way. This is kind of like C++'s copy and swap idiom, but built into the language.
Jan 10 2013
parent "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 10 January 2013 at 23:49:40 UTC, monarch_dodra wrote:
 On Thursday, 10 January 2013 at 23:37:14 UTC, Namespace wrote:
 Without a declared opAssign, this

  S s3;
  s3 = s1;

 also calls the postblit. That is strange.
If there is no user declared opAssign, then opAssign is implemented in terms of postblit. It's designed that way. This is kind of like C++'s copy and swap idiom, but built into the language.
And that was what I did not know and could not find anywhere. So it is enough if I declare a postblit. And yes, benchmarks are hard. ;)
Jan 11 2013
prev sibling parent "David Nadlinger" <see klickverbot.at> writes:
On Thursday, 10 January 2013 at 23:37:14 UTC, Namespace wrote:
 Without a declared opAssign, this

   S s3;
   s3 = s1;

 also calls the postblit. That is strange.
Think of it like this: Blit means bit-by-bit copy, so a postblit is a function that is invoked on the result of every bit-by-bit copy operation. The default behavior for struct assignment is precisely to copy over the contents, so it makes sense for the postblit to be invoked in that case. David
Jan 10 2013
prev sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 10 January 2013 at 23:03:30 UTC, Namespace wrote:
 And what should I use, this(this) or opAssign? I thougth that 
 it is unimportant,
 but that changed my mind: http://dpaste.dzfl.pl/36ce3688
BTW, answered to the best of my abilities, taking into account your link expired, so I don't have as much context as you tried to offer.
Jan 10 2013
parent reply "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 10 January 2013 at 23:30:35 UTC, monarch_dodra wrote:
 On Thursday, 10 January 2013 at 23:03:30 UTC, Namespace wrote:
 And what should I use, this(this) or opAssign? I thougth that 
 it is unimportant,
 but that changed my mind: http://dpaste.dzfl.pl/36ce3688
BTW, answered to the best of my abilities, taking into account your link expired, so I don't have as much context as you tried to offer.
It is private, sorry. Here as public: http://dpaste.dzfl.pl/ab3c7a5c
Jan 10 2013
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Thursday, 10 January 2013 at 23:35:19 UTC, Namespace wrote:
 On Thursday, 10 January 2013 at 23:30:35 UTC, monarch_dodra 
 wrote:
 On Thursday, 10 January 2013 at 23:03:30 UTC, Namespace wrote:
 And what should I use, this(this) or opAssign? I thougth that 
 it is unimportant,
 but that changed my mind: http://dpaste.dzfl.pl/36ce3688
BTW, answered to the best of my abilities, taking into account your link expired, so I don't have as much context as you tried to offer.
It is private, sorry. Here as public: http://dpaste.dzfl.pl/ab3c7a5c
Yeah, but if you re-arrange the tests, then you get opposite results... http://dpaste.dzfl.pl/fork/c52f290a Benchmarking is hard. You could try maybe viewing the disassembly instead?
Jan 10 2013
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Friday, 11 January 2013 at 00:02:48 UTC, monarch_dodra wrote:
 On Thursday, 10 January 2013 at 23:35:19 UTC, Namespace wrote:
 On Thursday, 10 January 2013 at 23:30:35 UTC, monarch_dodra 
 wrote:
 On Thursday, 10 January 2013 at 23:03:30 UTC, Namespace wrote:
 And what should I use, this(this) or opAssign? I thougth 
 that it is unimportant,
 but that changed my mind: http://dpaste.dzfl.pl/36ce3688
BTW, answered to the best of my abilities, taking into account your link expired, so I don't have as much context as you tried to offer.
It is private, sorry. Here as public: http://dpaste.dzfl.pl/ab3c7a5c
Yeah, but if you re-arrange the tests, then you get opposite results... http://dpaste.dzfl.pl/fork/c52f290a
Sorry: http://dpaste.dzfl.pl/9ff9b84a
Jan 10 2013