www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Struct Union behavior

reply Voitech <woipoi gmail.com> writes:
Hello, i am new to D language and trying to learn it by coding.
I compile my programs on Xubuntu 14.04 with DMD64 D Compiler 
v2.069.2.
So i have a struct/union which contains two fields representing 
real and string values:

public union Element
{
	private real _value;
	private string _rawValue;

	 property{
		real value(){
			return _value;
		}
		void value(real value){
			_value=value;
		}

	}
	 property {
		ref string rawValue(){
			return _rawValue;
		}
		void rawValue(ref string value){
			_rawValue=value;
		}

	}

	
	public Element opBinary(string op)(Element other){
		Element newElement;
		real value=mixin("this.value "~op~"other.value");
		newElement.value=value;
		return newElement;
	}

	public bool opEquals(Element other){
		if(this.rawValue == null && other.rawValue == null){
			return this.opEquals(other.rawValue);
		}
		return this.opEquals(other.value);
	}
	public bool opEquals(real value){
		return this.value==value;
	}
	public bool opEquals(string rawValue){
		return this.rawValue==rawValue;
	}

	unittest{
		Element e1 = {4},e2 ={5};
		writeln("e1 is at address: ",&e1);
		writeln("e2 is at address: ",&e2);
		writeln("e1.value is at address: ",&e1._value);
		writeln("e2.value is at address: ",&e2._value);
		assert(e1+e2==9);
	}

	unittest{
		Element s1={_rawValue:"+"},s2,s3,s4;
		writeln("s1 is at address: ",&s1);
		writeln("s2 is at address: ",&s2);
		writeln("s3 is at address: ",&s3);
		writeln("s1.value is at address: ",&s1._value);
		writeln("s2.value is at address: ",&s2._value);
		writeln("s3.value is at address: ",&s3._value);
		writeln("s4.value is at address: ",&s4._value);
		writeln("s1.rawValue ",s1._rawValue);
		writeln("s1.value: ",s1._value);
		writeln("s2.value: ",s2._value);
		writeln("s3.value: ",s3._value);
		writeln("s4.value: ",s4._value );
		assert(s1!=s2);
	}
}

The unit test results are:

e1 is at address: 7FFCEFBA7510
e2 is at address: 7FFCEFBA7520
e1.value is at address: 7FFCEFBA7510
e2.value is at address: 7FFCEFBA7520
s1 is at address: 7FFCEFBA7500
s2 is at address: 7FFCEFBA7510
s3 is at address: 7FFCEFBA7520
s1.value is at address: 7FFCEFBA7500
s2.value is at address: 7FFCEFBA7510
s3.value is at address: 7FFCEFBA7520
s4.value is at address: 7FFCEFBA7530
s1.rawValue +
s1.value: 0.125
s2.value: 4
s3.value: 5
s4.value: 9

Can anyone tell me why s2,s3,s4 have initialized _value field?  
Shouldn't it be collected by GC when first unit test (with e1,e2) 
finishes ? If not how to handle this behavior, to use union 
without preinitialized fields.
Jan 06 2016
parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
On Wednesday, 6 January 2016 at 11:39:44 UTC, Voitech wrote:
 Hello, i am new to D language and trying to learn it by coding.
 I compile my programs on Xubuntu 14.04 with DMD64 D Compiler 
 v2.069.2.
 So i have a struct/union which contains two fields representing 
 real and string values:

 public union Element
 {
 	private real _value;
 	private string _rawValue;

 	 property{
 		real value(){
 			return _value;
 		}
 		void value(real value){
 			_value=value;
 		}

 	}
 	 property {
 		ref string rawValue(){
 			return _rawValue;
 		}
 		void rawValue(ref string value){
 			_rawValue=value;
 		}

 	}

 	
 	public Element opBinary(string op)(Element other){
 		Element newElement;
 		real value=mixin("this.value "~op~"other.value");
 		newElement.value=value;
 		return newElement;
 	}

 	public bool opEquals(Element other){
 		if(this.rawValue == null && other.rawValue == null){
 			return this.opEquals(other.rawValue);
 		}
 		return this.opEquals(other.value);
 	}
 	public bool opEquals(real value){
 		return this.value==value;
 	}
 	public bool opEquals(string rawValue){
 		return this.rawValue==rawValue;
 	}

 	unittest{
 		Element e1 = {4},e2 ={5};
 		writeln("e1 is at address: ",&e1);
 		writeln("e2 is at address: ",&e2);
 		writeln("e1.value is at address: ",&e1._value);
 		writeln("e2.value is at address: ",&e2._value);
 		assert(e1+e2==9);
 	}

 	unittest{
 		Element s1={_rawValue:"+"},s2,s3,s4;
 		writeln("s1 is at address: ",&s1);
 		writeln("s2 is at address: ",&s2);
 		writeln("s3 is at address: ",&s3);
 		writeln("s1.value is at address: ",&s1._value);
 		writeln("s2.value is at address: ",&s2._value);
 		writeln("s3.value is at address: ",&s3._value);
 		writeln("s4.value is at address: ",&s4._value);
 		writeln("s1.rawValue ",s1._rawValue);
 		writeln("s1.value: ",s1._value);
 		writeln("s2.value: ",s2._value);
 		writeln("s3.value: ",s3._value);
 		writeln("s4.value: ",s4._value );
 		assert(s1!=s2);
 	}
 }

 The unit test results are:

 e1 is at address: 7FFCEFBA7510
 e2 is at address: 7FFCEFBA7520
 e1.value is at address: 7FFCEFBA7510
 e2.value is at address: 7FFCEFBA7520
 s1 is at address: 7FFCEFBA7500
 s2 is at address: 7FFCEFBA7510
 s3 is at address: 7FFCEFBA7520
 s1.value is at address: 7FFCEFBA7500
 s2.value is at address: 7FFCEFBA7510
 s3.value is at address: 7FFCEFBA7520
 s4.value is at address: 7FFCEFBA7530
 s1.rawValue +
 s1.value: 0.125
 s2.value: 4
 s3.value: 5
 s4.value: 9

 Can anyone tell me why s2,s3,s4 have initialized _value field?  
 Shouldn't it be collected by GC when first unit test (with 
 e1,e2) finishes ? If not how to handle this behavior, to use 
 union without preinitialized fields.
Probably because you are accessing uninitialised memory. the values 4,5,9 appear in the first unittest and are left on the stack. Unions ,unlike structs, do not initialise their fields because it does not make sense to do so because the memory aliases. This can be observed by looking at the size of element (16 bytes) which is less than the size of an array (on 64 bit systems) , 2*8 bytes plus size of a real (8 or 10 bytes (x86/64)). other things unrelated to your question. Things are public by default so the 'public's are redundant. strings are arrays so (most of the time) don't need ref, as the elements are accessed through a pointer. See also Algebraic for cases (most) when you want to know the type of the value of the union. Comparisons to null should use 'is' expressions Having _value and _rawvalue as private and then providing getters and setters is redundant. the same behaviour can be achieved by making the public. getters and setters are for either heaving only a getter or calling a function when a field is changed (e.g. updating a cache) Nic
Jan 06 2016
parent Voitech <woipoi gmail.com> writes:
On Wednesday, 6 January 2016 at 12:25:31 UTC, Nicholas Wilson 
wrote:
 Probably because you are accessing uninitialised memory. the 
 values 4,5,9 appear in the first unittest and are left on the 
 stack. Unions ,unlike structs, do not initialise their fields 
 because it does not make sense to do so because the memory 
 aliases. This can be observed by looking at the size of element 
 (16 bytes) which is less than the size of an array (on 64 bit 
 systems) , 2*8 bytes plus size of a real (8 or 10 bytes 
 (x86/64)).

 [...]
Thank you for your answer it was very helpful :) Cheers.
Jan 06 2016