Thread overview | ||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
May 20, 2010 Newbie: copy, assignment of class instances | ||||
---|---|---|---|---|
| ||||
Attachments:
| Given: class A { int x, y; } class B : A { int z; } B foo = new B, bar = new B; scope B alpha = new B; Q1: How do I copy the member variables contributed by base class A from "foo" to "bar"? In C++: (A &) bar = foo; Q2: How do I do a deepcopy of foo to bar? In C++: bar = foo; Q3: Is the object "alpha" on the stack (per documentation)? Q4: What happens when I do "alpha = foo;"? "printf( "%p\n", alpha);" indicates that the address of "alpha" has changed. Thanks, Larry |
May 20, 2010 Re: Newbie: copy, assignment of class instances | ||||
---|---|---|---|---|
| ||||
Posted in reply to Larry Luther | Larry Luther <larry.luther@dolby.com> wrote: > Given: > > class A { > int x, y; > } > > class B : A { > int z; > } > > B > foo = new B, > bar = new B; > > scope B > alpha = new B; > > Q1: How do I copy the member variables contributed by base class A > from "foo" to "bar"? > In C++: (A &) bar = foo; You can't. If you need this functionality, use a specialized function. > Q2: How do I do a deepcopy of foo to bar? > In C++: bar = foo; You don't. If you need this functionality, use a specialized function. This should, to keep symmetry with other D features, probably be called dup. Possibly deepdup, as the other dups don't do deep copy. It is also worth noting that 'bar = foo;' does not perform deep copying in C++, it only copies the immediate members, whereas deep copy would follow pointers and deep copy those, too. btw, if what you're referring to is not the deep copy explained above, but merely a shallow copy (of the instance, not the reference), the function should be called dup. > Q3: Is the object "alpha" on the stack (per documentation)? Yes. Proof: void main( ) { A a = new A( ); scope A b = new A( ); writefln( "%p, %p, %p", cast(void*)a, cast(void*)b, cast(void*)&a ); } > Q4: What happens when I do "alpha = foo;"? > "printf( "%p\n", alpha);" indicates that the address of "alpha" has changed. 'scope B alpha;' allocates stack space for a reference to a B, and space for an instance of B. If the pointer changes, it is simply no longer referencing the instance on the stack. -- Simen |
May 20, 2010 Re: Newbie: copy, assignment of class instances | ||||
---|---|---|---|---|
| ||||
Posted in reply to Larry Luther | Larry Luther: > class A { > int x, y; > } > > class B : A { > int z; > } > > B > foo = new B, > bar = new B; > > scope B > alpha = new B; Don't write code like this, it's not easy to write: > B > foo = new B, > bar = new B; Write it this way: B foo = new B, B bar = new B; Or this way: auto foo = new B, auto bar = new B; > Q1: How do I copy the member variables contributed by base class A > from "foo" to "bar"? > In C++: (A &) bar = foo; There is no standard way to do this. In general you don't need to copy classes or their contents, because they are on the heap and managed by the GC. If you want to copy their contents you have to add methods written by you that perform the copy you need. > Q2: How do I do a deepcopy of foo to bar? > In C++: bar = foo; In general you don't do it. There is no standard way to perform a deep copy. You can write your code to do it, but it's not easy to write. So far I have never had to perform a deep copy on D classes. For structs take a look at postblit too: http://www.digitalmars.com/d/2.0/struct.html#StructPostblit > Q3: Is the object "alpha" on the stack (per documentation)? In this case with ldc and dmd alpha is on the stack, you can see also reading the produced asm. On the docs you can read the rules that must be satisfied for scoped classes to be really allocated on the stack. > Q4: What happens when I do "alpha = foo;"? > "printf( "%p\n", alpha);" indicates that the address of "alpha" has changed. alpha is on the stack, but beside alpha on the stack there is also the reference to alpha. So such reference gets rewritten. Generally in D it's not a good idea to reassign the reference to a scoped class (some months ago I have even suggested to turn this operation into a syntax error) because when the scope ends, the class referenced by the reference to alpha gets collected, so if you change such reference to something else, it is such something else that gets collected. I am not sure what happens here, but this can be a source of bad troubles. This is probably why Walter was thinking of removing the scope attribute for classes. Bye, bearophile |
May 20, 2010 Re: Newbie: copy, assignment of class instances | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | > Generally in D it's not a good idea to reassign the reference to a scoped class
You can see it with this little D2 program:
import std.stdio: printf;
class Foo {
int x;
this(int xx) { this.x = xx; }
~this() { printf("Foo(%d) destructor\n", this.x); }
}
void main() {
scope Foo f1 = new Foo(1);
Foo f2 = new Foo(2);
f1 = f2;
}
It prints just:
Foo(2) destructor
In general this is not good.
Bye,
bearophile
|
May 20, 2010 Re: Newbie: copy, assignment of class instances | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | http://d.puremagic.com/issues/show_bug.cgi?id=4214 |
May 20, 2010 Re: Newbie: copy, assignment of class instances | ||||
---|---|---|---|---|
| ||||
Posted in reply to Larry Luther Attachments:
| Thank you for the clarifications. I'm trying to do a shallow copy. After reading Simen & bearophile, I would add a "copy" member function: class A { int x, y; void copy (in A a) { x = a.x; y = a.y; } } class B : A { int z; void copy (in B b) { super.copy( b); z = b.z; } } B foo = new B, B bar = new B; Q: Do I copy the member variables contributed by class A from "foo" to "bar", this way: "(cast(A) bar).copy( foo);"? Or maybe "bar.A.copy( foo);"? Larry |
May 20, 2010 Re: Newbie: copy, assignment of class instances | ||||
---|---|---|---|---|
| ||||
Posted in reply to Larry Luther | Larry Luther:
> B foo = new B,
> B bar = new B;
This is not valid D code, you have to use something like:
B foo = new B;
B bar = new B;
I suggest you to actually try to compile and run your little test programs. If you compile this:
class A {
int x, y;
void copy(A a) {
x = a.x;
y = a.y;
}
}
class B : A { // line 10
int z;
void copy(B b) {
super.copy(b);
z = b.z;
}
}
void main() {
B foo = new B;
B bar = new B;
}
You get this (badly written) error:
test.d(10): Error: class test2.B test2.A.copy(A a) is hidden by B
This works:
import std.stdio: writeln;
import std.string: format;
template ExceptionTemplate() {
this() {
super(this.classinfo.name);
}
this(string msg) {
super(this.classinfo.name ~ ": " ~ msg);
}
}
class ArgumentException: Exception {
mixin ExceptionTemplate;
}
class A {
int x, y;
this(int xx, int yy) {
this.x = xx;
this.y = yy;
}
void copyFrom(Object other) {
auto o = cast(typeof(this))other;
if (o is null)
throw new ArgumentException("Some message here...");
x = o.x;
y = o.y;
}
override string toString() {
return format("A(%d, %d)", this.x, this.y);
}
}
class B : A {
int z;
this(int xx, int yy, int zz) {
super(xx, yy);
this.z = zz;
}
override void copyFrom(Object other) {
auto o = cast(typeof(this))other;
if (o is null)
throw new Exception("..."); // use a more specific exception here
super.copyFrom(other);
z = o.z;
}
override string toString() {
return format("B(%d, %d, %d)", this.x, this.y, this.z);
}
}
void main() {
B foo = new B(1, 2, 3);
B bar = new B(4, 5, 6);
writeln("foo = ", foo);
writeln("bar = ", bar);
foo.copyFrom(bar);
writeln("foo = ", foo);
writeln("bar = ", bar);
}
Output:
foo = B(1, 2, 3)
bar = B(4, 5, 6)
foo = B(4, 5, 6)
bar = B(4, 5, 6)
An alternative implementation:
import std.stdio: writeln;
import std.string: format;
template ExceptionTemplate() {
this() {
super(this.classinfo.name);
}
this(string msg) {
super(this.classinfo.name ~ ": " ~ msg);
}
}
class ArgumentException: Exception {
mixin ExceptionTemplate;
}
class A {
int x, y;
this(int xx, int yy) {
this.x = xx;
this.y = yy;
}
void copyFrom(typeof(this) other) {
x = other.x;
y = other.y;
}
override string toString() {
return format("A(%d, %d)", this.x, this.y);
}
}
class B : A {
int z;
this(int xx, int yy, int zz) {
super(xx, yy);
this.z = zz;
}
override void copyFrom(typeof(super) other) {
auto o = cast(typeof(this))other;
if (o is null)
throw new ArgumentException("Some message here...");
super.copyFrom(other);
z = o.z;
}
override string toString() {
return format("B(%d, %d, %d)", this.x, this.y, this.z);
}
}
void main() {
B foo = new B(1, 2, 3);
B bar = new B(4, 5, 6);
writeln("foo = ", foo);
writeln("bar = ", bar);
foo.copyFrom(bar);
writeln("foo = ", foo);
writeln("bar = ", bar);
}
In other languages an operator as "isa" replaces the less nice looking dynamic cast followed by null test.
Bye,
bearophile
|
May 20, 2010 Re: Newbie: copy, assignment of class instances | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile Attachments:
| I did not get an error when building and running with DMD 2.042: import std.stdio; class A { int x, y; void copy (in A a) { x = a.x; y = a.y; } void dump (string s) { writefln( "%s.A = { %s, %s }", s, x, y); } } class B : A { int z; void copy (in B b) { super.copy( b); z = b.z; } void dump (string s) { super.dump( s); writefln( "%s.B = { %s }", s, z); } } void main () { B foo = new B; B bar = new B; foo.x = 3; foo.y = 5; foo.z = 17; bar.x = 7; bar.y = 11; bar.z = 13; foo.dump( "foo"); bar.dump( "bar"); bar.copy( foo); bar.dump( "bar#2"); } Which prints: foo.A = { 3, 5 } foo.B = { 17 } bar.A = { 7, 11 } bar.B = { 13 } bar#2.A = { 3, 5 } bar#2.B = { 17 } |
May 20, 2010 Re: Newbie: copy, assignment of class instances | ||||
---|---|---|---|---|
| ||||
Posted in reply to Larry Luther | Larry Luther:
> void copy (in A a) {
In D2 it's better to use "const" or "immutable" instead of "in".
Here's one version of the code const-aware:
import std.stdio: writeln;
import std.string: format;
template ExceptionTemplate() {
this() {
super(this.classinfo.name);
}
this(string msg) {
super(this.classinfo.name ~ ": " ~ msg);
}
}
class ArgumentException: Exception {
mixin ExceptionTemplate;
}
class A {
int x, y;
this(int xx, int yy) {
this.x = xx;
this.y = yy;
}
void copyFrom(const Object other) {
const o = cast(typeof(this))other;
if (o is null)
throw new ArgumentException("Some message here...");
x = o.x;
y = o.y;
}
override string toString() const {
return format("A(%d, %d)", this.x, this.y);
}
}
class B : A {
int z;
this(int xx, int yy, int zz) {
super(xx, yy);
this.z = zz;
}
override void copyFrom(const Object other) {
const o = cast(typeof(this))other;
if (o is null)
throw new ArgumentException("Some message here...");
super.copyFrom(other);
z = o.z;
}
override string toString() const {
return format("B(%d, %d, %d)", this.x, this.y, this.z);
}
}
void main() {
B foo = new B(1, 2, 3);
B bar = new B(4, 5, 6);
writeln("foo = ", foo);
writeln("bar = ", bar);
foo.copyFrom(bar);
writeln("foo = ", foo);
writeln("bar = ", bar);
}
Bye,
bearophile
|
May 20, 2010 Re: Newbie: copy, assignment of class instances | ||||
---|---|---|---|---|
| ||||
Posted in reply to Larry Luther | Larry Luther:
> I did not get an error when building and running with DMD 2.042:
I am using dmd v2.046, and I have taken the good habit of compiling with -w (warnings on).
It seems this error I see is a blocking warning. It's a warning badly written, but do you agree it is saying something important? I presume your code can lead to bugs. I don't know why this is a warning instead of a true error...
On your code it also complains for a missed "override" that is a good thing that eventually will become obligatory even without -w.
When you post here I suggest you to avoid using HTML and use pure text.
Bye,
bearophile
|
Copyright © 1999-2021 by the D Language Foundation