www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Copying reference types by value

reply Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
Hello all,

Suppose I have a couple of variables a, b that are reference types (e.g. arrays
or classes).  Then, setting a = b will mean that the two reference the same
entity.

If they're arrays, one can copy the values readily by setting a[] = b[], but
this isn't a generic solution -- suppose instead of arrays, I a and b are
instances of

	class A {
		int one;
		double two;
		size_t three;

		this(int _one, double _two, size_t _three)
		{
			one = _one;
			two = _two;
			three = _three;
		}
	}

Now, I can see several solutions.  The first is just to define a generic copy
function, like,

	void copyMyClass(const A from, ref A to) { ... }

... which copies over values.  However, as a general solution that seems a bit
dodgy as it presumes I have the right to read and write all internal values of
the class.

Defining a .dup method doesn't seem appropriate either because although it
allows me to duplicate the values, setting

	a = b.dup;

will mean that a now becomes a new object, and any other entities that were
pointing at the original a will suddenly become decoupled from its values.  So,
if I do,

	c = a;
	a = b.dup;

... I will no longer have c equal to a.

So, can anyone recommend an appropriate general method for copying the values of
one reference type instance to another?  Perhaps an appropriate operator to
overload?

Thanks & best wishes,

    -- Joe
Apr 17 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/17/2013 09:17 AM, Joseph Rushton Wakeling wrote:

 Defining a .dup method doesn't seem appropriate either because 
although it
 allows me to duplicate the values, setting

 	a = b.dup;

 will mean that a now becomes a new object, and any other entities 
that were
 pointing at the original a will suddenly become decoupled from its 
values. So,
 if I do,

 	c = a;
 	a = b.dup;

 ... I will no longer have c equal to a.
I haven't used it anywhere but I did think about this very issue just the other day. I thought about defining a takeOver() member function that does what you need: // take over the members of b a.takeOver(b); // b becomes null (or .init?) Using takeOver() along with dup(), one can copy state: a.takeOver(b.dup()); Of course there can be a wrapper function for that. :) But I am curious as well. What do others do in such cases? Are there accepted solutions in other languages like Java and C#? Ali
Apr 17 2013
parent reply Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On 04/17/2013 06:54 PM, Ali Çehreli wrote:
 I haven't used it anywhere but I did think about this very issue just the other
 day. I thought about defining a takeOver() member function that does what you
need:
 
   // take over the members of b
   a.takeOver(b); // b becomes null (or .init?)
Ahh, so you mean that the current members of a get discarded and replaced with those of b?
 Using takeOver() along with dup(), one can copy state:
 
   a.takeOver(b.dup());
 
 Of course there can be a wrapper function for that. :)
It's an intriguing thought. How do you get round the issue of private variables ... ? And what's the benefit over a method like, say, a.copyFrom(b); ... which just copies values between corresponding variables? (Leaving aside that takeOver has applications of its own -- I mean my question purely in the context of copying values.)
Apr 17 2013
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/17/2013 10:09 AM, Joseph Rushton Wakeling wrote:

 On 04/17/2013 06:54 PM, Ali Çehreli wrote:
 I haven't used it anywhere but I did think about this very issue 
just the other
 day. I thought about defining a takeOver() member function that does 
what you need:
    // take over the members of b
    a.takeOver(b); // b becomes null (or .init?)
Ahh, so you mean that the current members of a get discarded and
replaced with
 those of b?
Yes but as I said I am not sure how useful or needed this whole thing is. The language handles copy, move, and assignment for structs. takeOver() seems to be a primitive operation for classes.
 Using takeOver() along with dup(), one can copy state:

    a.takeOver(b.dup());

 Of course there can be a wrapper function for that. :)
It's an intriguing thought. How do you get round the issue of
private variables
 ... ?
takeOver()'s parameter is presumably the same type as the class's so the private members are accessible. Of course any member may be well encapsulated; then, takeOver() depends on similar functionality that those members provide, perhaps through member functions that are again named takeOver() but there is no standard for it. A framework may require that such "take over" member functions should be marked by a specific UDA.
  And what's the benefit over a method like, say,

 	a.copyFrom(b);
That's what I meant by "a wrapper function." But I think move is a more fundamental operation that elides a copy. If we had only copyFrom(), then the following would indeed need to copy: // foo() returns a class object a.copyFrom(foo()); On the other hand, takeOver() would have the ability to move the members of the returned rvalue object without needing to copy.
 ... which just copies values between corresponding variables? 
(Leaving aside
 that takeOver has applications of its own -- I mean my question 
purely in the
 context of copying values.)
Agreed. Ali
Apr 17 2013
parent reply Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On 04/17/2013 10:29 PM, Ali Çehreli wrote:
 Yes but as I said I am not sure how useful or needed this whole thing is.
 
 The language handles copy, move, and assignment for structs. takeOver() seems
to
 be a primitive operation for classes.
Could you expand a bit on that? Just that I'm not sure I understand your meaning completely, and I'm curious. :-)
 That's what I meant by "a wrapper function." But I think move is a more
 fundamental operation that elides a copy. If we had only copyFrom(), then the
 following would indeed need to copy:
 
     // foo() returns a class object
     a.copyFrom(foo());
 
 On the other hand, takeOver() would have the ability to move the members of the
 returned rvalue object without needing to copy.
OK, clear. In fact seems possible that copying vs. takeover might be useful to define separately and use whichever is optimal for the given use-case.
 Agreed.
I'd assumed this problem would be some fairly straightforward aspect of the language that I just wasn't familiar with, so I'm quite struck by the fact that it actually seems a non-trivial problem.
Apr 18 2013
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 04/18/2013 06:22 AM, Joseph Rushton Wakeling wrote:> On 04/17/2013 
10:29 PM, Ali Çehreli wrote:
 Yes but as I said I am not sure how useful or needed this whole 
thing is.
 The language handles copy, move, and assignment for structs. 
takeOver() seems to
 be a primitive operation for classes.
Could you expand a bit on that? Just that I'm not sure I understand your meaning completely, and I'm curious. :-)
Being value types, structs enjoy automatic handling of copy, assignment, and in the case of rvalues, move. struct S { int i; } S makeS() { return S(); } void main() { auto a = S(); auto b = a; // a is copied to b b = a; // a is assigned to b b = makeS(); // the returned rvalue is 'moved' to b } Of course that works only for structs with simple value members. When the automatic handling is not sufficient or does the wrong thing, then the programmer must provide this(this), opAssign(), or ~this(). Things get more interesting when the members are mutable or immutable references. With the above definition of S, all of the following compile: immutable(S) imm0; S mut = imm0; // immutable to mutable immutable(S) imm1 = mut; // mutable to immutable immutable(S) imm2 = imm0; // immutable to immutable Now naively add another member to S: struct S { int i; int[] arr; // <-- added } Only the latter of the three assignments compile: immutable(S) imm0; S mut = imm0; // compilation ERROR immutable(S) imm1 = mut; // compilation ERROR immutable(S) imm2 = imm0; // compiles Anyway... I am trying to wrap up what I have learned so far before going any further. :) For classes, none of these operations make sense: There is no automatic copying, no automatic assignment, nor there are rvalues to move.
 I'd assumed this problem would be some fairly straightforward aspect 
of the
 language that I just wasn't familiar with, so I'm quite struck by the 
fact that
 it actually seems a non-trivial problem.
My experience has been with C++ so I don't know how this is solved in Java or C#. Maybe this is not a problem with the common idioms in those languages, which would also mean that this is not a problem with D classes. Rather, if one has decided to go with a class, then value semantics were not a consideration to begin with. Ali
Apr 18 2013