www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Struct inheritance

reply "amber" <amber.swan gmail.com> writes:
Hi,

Is it possible in D to have inheritance using value types, i.e. 
structs?

Also I don't quite understand how copy ctors work in D. Do I need 
to implement opAssign(S other) {}, or this(this) {} and what's 
the difference between these two?

Thanks,
Amber
Feb 24 2015
next sibling parent reply "Tobias Pankrath" <tobias pankrath.net> writes:
On Tuesday, 24 February 2015 at 12:05:51 UTC, amber wrote:
 Hi,

 Is it possible in D to have inheritance using value types, i.e. 
 structs?
No runtime polymorphism, but a kind of sub typing via alias this. struct S { void foo() { writeln("S.foo"); } struct T { S s; alias s this; } T t; t.foo(); // prints S.foo
 Also I don't quite understand how copy ctors work in D. Do I 
 need to implement opAssign(S other) {}, or this(this) {} and 
 what's the difference between these two?
If available, opAssign will be used in an assignment like x = y; You're custom opAssign can take arbitrary parameter types, so typeof(y) does not have to be typeof(x). postblit is used for copy construction. This could be assignment if no opAssign is provided (not sure about this), but also e.g. passing parameter by value or returning from a function.
Feb 24 2015
parent "amber" <amber.swan gmail.com> writes:
On Tuesday, 24 February 2015 at 12:16:43 UTC, Tobias Pankrath 
wrote:
 On Tuesday, 24 February 2015 at 12:05:51 UTC, amber wrote:
 Hi,

 Is it possible in D to have inheritance using value types, 
 i.e. structs?
No runtime polymorphism, but a kind of sub typing via alias this. struct S { void foo() { writeln("S.foo"); } struct T { S s; alias s this; } T t; t.foo(); // prints S.foo
 Also I don't quite understand how copy ctors work in D. Do I 
 need to implement opAssign(S other) {}, or this(this) {} and 
 what's the difference between these two?
If available, opAssign will be used in an assignment like x = y; You're custom opAssign can take arbitrary parameter types, so typeof(y) does not have to be typeof(x). postblit is used for copy construction. This could be assignment if no opAssign is provided (not sure about this), but also e.g. passing parameter by value or returning from a functions
Thank you Tobias I get it now. /amber
Feb 24 2015
prev sibling next sibling parent reply ketmar <ketmar ketmar.no-ip.org> writes:
On Tue, 24 Feb 2015 12:05:50 +0000, amber wrote:

 Hi,
=20
 Is it possible in D to have inheritance using value types, i.e. structs?
=20
 Also I don't quite understand how copy ctors work in D. Do I need to
 implement opAssign(S other) {}, or this(this) {} and what's the
 difference between these two?
there is no "copy constructor" in D. structs are copied by `memcpy()`,=20 and then compiler calls "postblit" aka `this(this)`. it may seem like=20 constructor, but it's not. it's a "fixup", that fixes inconsistencies=20 that are left by `memcpy()`. i.e. when postblit is called, structure is=20 already copied. and `opAssign` is... well, overloading of "=3D" operator. it has to=20 manually create a structure copy and manually copy everything you need.=20 and it will never be called by compiler "behind the scenes", like=20 postblit.=
Feb 24 2015
parent ketmar <ketmar ketmar.no-ip.org> writes:
On Tue, 24 Feb 2015 18:19:39 +0000, ketmar wrote:

 On Tue, 24 Feb 2015 12:05:50 +0000, amber wrote:
=20
 Hi,
=20
 Is it possible in D to have inheritance using value types, i.e.
 structs?
=20
 Also I don't quite understand how copy ctors work in D. Do I need to
 implement opAssign(S other) {}, or this(this) {} and what's the
 difference between these two?
=20 there is no "copy constructor" in D. structs are copied by `memcpy()`, and then compiler calls "postblit" aka `this(this)`. it may seem like constructor, but it's not. it's a "fixup", that fixes inconsistencies that are left by `memcpy()`. i.e. when postblit is called, structure is already copied. =20 and `opAssign` is... well, overloading of "=3D" operator. it has to manually create a structure copy and manually copy everything you need. and it will never be called by compiler "behind the scenes", like postblit.
oops. of course, you already has a struct for `opAssign` -- it need=20 `this` after all! ;-) but no automatic copying. it's just a function=20 call, nothing magic here.=
Feb 24 2015
prev sibling parent reply ketmar <ketmar ketmar.no-ip.org> writes:
On Tue, 24 Feb 2015 12:05:50 +0000, amber wrote:

 Hi,
=20
 Is it possible in D to have inheritance using value types, i.e. structs?
=20
 Also I don't quite understand how copy ctors work in D. Do I need to
 implement opAssign(S other) {}, or this(this) {} and what's the
 difference between these two?
=20
 Thanks,
 Amber
p.s. sometimes compiler can use "move" instead of "copy" for structures.=20 in this case it will not call postblit. so if you have some fields in=20 your struct that depends of the structure address... you're in trouble.=
Feb 24 2015
parent "H. S. Teoh via Digitalmars-d-learn" <digitalmars-d-learn puremagic.com> writes:
On Tue, Feb 24, 2015 at 06:22:05PM +0000, ketmar via Digitalmars-d-learn wrote:
 On Tue, 24 Feb 2015 12:05:50 +0000, amber wrote:
 
 Hi,
 
 Is it possible in D to have inheritance using value types, i.e.
 structs?
 
 Also I don't quite understand how copy ctors work in D. Do I need to
 implement opAssign(S other) {}, or this(this) {} and what's the
 difference between these two?
 
 Thanks,
 Amber
p.s. sometimes compiler can use "move" instead of "copy" for structures. in this case it will not call postblit. so if you have some fields in your struct that depends of the structure address... you're in trouble.
Yes, basically, D structs are value types, and quite unlike C++ structs. It's a trap to assume C++-like semantics for D structs, because they are actually very different beasts. D structs should not rely on their own address remaining static, because move semantics will cause problems, for example: struct S { int x; int* p; this(int _x) { x = _x; p = &x; // uh-oh } void method() { *p++; // by the time this runs, the struct may // have moved } } S makeStruct() { return S(1); } void main() { auto s = makeStruct(); s.method(); assert(s.x == 2); // KABOOM } The problem is that returning S from makeStruct() makes a bitwise copy of the struct into main's local variable s, which has a different address than the one created in makeStruct(). But s.p still points to the old address of s.x, which is now pointing to invalid memory. For even more fun, do this: void checkItOut(int x, S* s) { assert(x == 10); s.method(); assert(x == 10); // KABOOM } void main() { auto s = makeStruct(); s.method(); checkItOut(10, &s); } Depending on the specifics of your platform, the second assert in checkItOut() may fail, because s.method(), via the stale pointer s.p, will overwrite the stack location where the original s.x was (but which has gone out of scope and is now invalid), and that old location is now being used for one of the parameters of checkItOut(). So calling s.method() will silently corrupt the stack where the parameter is passed. tl;dr, the moral of the story is, don't rely on the address of structs in D staying the same, unless you REALLY know what you're doing. And even then, you're just 1/8 of an inch away from shooting yourself in the foot. T -- All problems are easy in retrospect.
Feb 24 2015