www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Array Operations and type inference

reply simendsjo <simen.endsjo pandavre.com> writes:
I'm new to D2, so please.. :)

The spec on Array Operations, 
http://www.digitalmars.com/d/2./arrays.html says:
"""A vector operation is indicated by the slice operator appearing as 
the lvalue of an =, +=, -=, *=, /=, %=, ^=, &= or |= operator."""

The following tests works fine as I expected:


	{
		double[3] a = [1,1,1];
		double[3] b;
		b[] = a[] + 3;
		assert(a == [1,1,1]);
		assert(b == [4,4,4]);
	}
	
	{
		double[3] a = [1,1,1];
		auto b = a;
		b[] = a[] + 3;
		assert(a == [1,1,1]);
		assert(b == [4,4,4]);
	}

But from here on I'm having problems...

	{
		double[] a = [1,1,1];
		double[] b;
		b[] = a[] + 3;
		assert(a == [1,1,1]);
		assert(b == [4,4,4]); // fails as b.length == 0.. Should the compiler 
say something?
	}
	
	{
		double[] a = [1,1,1];
		double[] b;
		b.length = a.length;
		b[] = a[] + 3;
		assert(a == [1,1,1]);
		assert(b == [4,4,4]); // Now it's fine
	}
	
	{
		double[3] a = [1,1,1];
		double[3] b = a[] + 3; // works although lvalue isn't a slice. Static 
arrays? Because it's an initial value?
		assert(a == [1,1,1]);
		assert(b == [4,4,4]);
	}
	
	{
		double[3] a = [1,1,1];
		auto b = a;
		b = a[] + 3; // And so does this.. Something to do with static arrays?
		assert(a == [1,1,1]);
		assert(b == [4,4,4]);
	}
	
	{ // Like the previous example, but with dynamic arrays..
		double[] a = [1,1,1];
		auto b = a;
		assert(a is b);
		b = a[] + 3;
		assert(a == [1,1,1]);
		//writeln(b); // access violation. Because of dynamic arrays?
	}	

	{ // Like above, but using slicing like the spec says.. Works fine
		double[] a = [1,1,1];
		auto b = a;
		assert(a is b);
		writeln(typeof(b).stringof); // double[]
		b[] = a[] + 3;
		assert(a == [4,4,4]); // a also changed. I expected this
		assert(b == [4,4,4]);
	}
	
	{
		double[3] a = [1,1,1];
		auto b = a[] + 3; // What happens here?
		writeln(typeof(b).stringof); // double[]
		assert(b.length == 3);
		assert(b.capacity == 0);
		//writeln(b); // access violation
	}
	
	{ // Same as above?
		double[3] a = [1,1,1];
		//writeln(a[] + 3); // access violation
	}
	
Aug 07 2010
next sibling parent Mafi <mafi example.org> writes:
Am 07.08.2010 14:10, schrieb simendsjo:
 I'm new to D2, so please.. :)

 The spec on Array Operations,
 http://www.digitalmars.com/d/2./arrays.html says:
 """A vector operation is indicated by the slice operator appearing as
 the lvalue of an =, +=, -=, *=, /=, %=, ^=, &= or |= operator."""

 The following tests works fine as I expected:


 {
 double[3] a = [1,1,1];
 double[3] b;
 b[] = a[] + 3;
 assert(a == [1,1,1]);
 assert(b == [4,4,4]);
 }

 {
 double[3] a = [1,1,1];
 auto b = a;
 b[] = a[] + 3;
 assert(a == [1,1,1]);
 assert(b == [4,4,4]);
 }

 But from here on I'm having problems...

 {
 double[] a = [1,1,1];
 double[] b;
 b[] = a[] + 3;
 assert(a == [1,1,1]);
 assert(b == [4,4,4]); // fails as b.length == 0.. Should the compiler
 say something?
 }

 {
 double[] a = [1,1,1];
 double[] b;
 b.length = a.length;
 b[] = a[] + 3;
 assert(a == [1,1,1]);
 assert(b == [4,4,4]); // Now it's fine
 }

 {
 double[3] a = [1,1,1];
 double[3] b = a[] + 3; // works although lvalue isn't a slice. Static
 arrays? Because it's an initial value?
 assert(a == [1,1,1]);
 assert(b == [4,4,4]);
 }

 {
 double[3] a = [1,1,1];
 auto b = a;
 b = a[] + 3; // And so does this.. Something to do with static arrays?
 assert(a == [1,1,1]);
 assert(b == [4,4,4]);
 }

 { // Like the previous example, but with dynamic arrays..
 double[] a = [1,1,1];
 auto b = a;
 assert(a is b);
 b = a[] + 3;
 assert(a == [1,1,1]);
 //writeln(b); // access violation. Because of dynamic arrays?
 }

 { // Like above, but using slicing like the spec says.. Works fine
 double[] a = [1,1,1];
 auto b = a;
 assert(a is b);
 writeln(typeof(b).stringof); // double[]
 b[] = a[] + 3;
 assert(a == [4,4,4]); // a also changed. I expected this
 assert(b == [4,4,4]);
 }

 {
 double[3] a = [1,1,1];
 auto b = a[] + 3; // What happens here?
 writeln(typeof(b).stringof); // double[]
 assert(b.length == 3);
 assert(b.capacity == 0);
 //writeln(b); // access violation
 }

 { // Same as above?
 double[3] a = [1,1,1];
 //writeln(a[] + 3); // access violation
 }
Hi, I don't the answer to all of your problems but what I can say you is: * D-Arrays are references to structs which point to the data * An arrayvariable on the left-hand-side of an assignment sets the reference of this variable. (no copy!) * An array slice is mostly the same as the array variable itself but if it's on the left-hand-side of an assignment, the data is copied from the right-hand-side. So for example your third example can't work because b is null and so there's no place you can copy the data to.
Aug 07 2010
prev sibling next sibling parent reply Mafi <mafi example.org> writes:
Hey, here Mafi again,
I thought about your snippets and here's what I have.

Am 07.08.2010 14:10, schrieb simendsjo:
 {
 double[3] a = [1,1,1];
 double[3] b;
 b[] = a[] + 3;
 assert(a == [1,1,1]);
 assert(b == [4,4,4]);
 }

 {
 double[3] a = [1,1,1];
 auto b = a;
 b[] = a[] + 3;
 assert(a == [1,1,1]);
 assert(b == [4,4,4]);
 }

 But from here on I'm having problems...

 {
 double[] a = [1,1,1];
 double[] b;
 b[] = a[] + 3;
 assert(a == [1,1,1]);
 assert(b == [4,4,4]); // fails as b.length == 0.. Should the compiler say
something?
 }
As I said in my first post b is null. Now the third line tries to _copy_ the result to b which is impossible. About your question: that the compiler complains would be difficult but in my opinion it should result in an runtime error.
 {
 double[] a = [1,1,1];
 double[] b;
 b.length = a.length;
 b[] = a[] + 3;
 assert(a == [1,1,1]);
 assert(b == [4,4,4]); // Now it's fine
 }
With setting b's length you (re)allocate(1) memory for the array so now there's place to copy to.
 {
 double[3] a = [1,1,1];
 double[3] b = a[] + 3; // works although lvalue isn't a slice. Static
 arrays? Because it's an initial value?
 assert(a == [1,1,1]);
 assert(b == [4,4,4]);
 }
You simply intialize the fixed-size array with a dynamic one. I'm not sure but I think the data is copied out of the dynamic temporary array to b.
 {
 double[3] a = [1,1,1];
 auto b = a;
 b = a[] + 3; // And so does this.. Something to do with static arrays?
 assert(a == [1,1,1]);
 assert(b == [4,4,4]);
 }
In the second line you initialize to a and then do the same as above. Note: In D fixed-size arrays are value types.
 { // Like the previous example, but with dynamic arrays..
 double[] a = [1,1,1];
 auto b = a;
 assert(a is b);
 b = a[] + 3;
 assert(a == [1,1,1]);
 //writeln(b); // access violation. Because of dynamic arrays?
 }
I have no idea. Maybe the array generated by the vector addition is kind of temporary and you have to copy. But it could also be a bug. Vector-operations are still quite buggy.
 { // Like above, but using slicing like the spec says.. Works fine
 double[] a = [1,1,1];
 auto b = a;
 assert(a is b);
 writeln(typeof(b).stringof); // double[]
 b[] = a[] + 3;
 assert(a == [4,4,4]); // a also changed. I expected this
 assert(b == [4,4,4]);
 }
Now you are copying to b(which references the same struct as a).
 {
 double[3] a = [1,1,1];
 auto b = a[] + 3; // What happens here?
 writeln(typeof(b).stringof); // double[]
 assert(b.length == 3);
 assert(b.capacity == 0);
 //writeln(b); // access violation
 }
It's the same as to steps before this(my english isn't ver good ;))
 { // Same as above?
I think it is.
 double[3] a = [1,1,1];
 //writeln(a[] + 3); // access violation
 }
(1)It's normally for reallocation when you need more space.
Aug 07 2010
parent Don <nospam nospam.com> writes:
Mafi wrote:
 Hey, here Mafi again,
 I thought about your snippets and here's what I have.
 
 Am 07.08.2010 14:10, schrieb simendsjo:
 { // Like the previous example, but with dynamic arrays..
 double[] a = [1,1,1];
 auto b = a;
 assert(a is b);
 b = a[] + 3;
 assert(a == [1,1,1]);
 //writeln(b); // access violation. Because of dynamic arrays?
 }
I have no idea. Maybe the array generated by the vector addition is kind of temporary and you have to copy. But it could also be a bug. Vector-operations are still quite buggy.
That is bug 4578, which has been fixed, and will be in the next compiler release.
Aug 07 2010
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Sorry for the late answer, I am quite busy now. Mafi has already answered, I
will probably repeat some things already said.

simendsjo:

Array ops currently have many bugs, they are fragile asm glass things, so when
you use them you have to be kind, if you misuse them a bit things crash and
burn :-) With time bugs will be removed. Currently D array ops are not
efficient for small arrays.


 	{
 		double[] a = [1,1,1];
 		double[] b;
 		b[] = a[] + 3;
 		assert(a == [1,1,1]);
 		assert(b == [4,4,4]); // fails as b.length == 0.. Should the compiler 
 say something?
 	}
That is wrong code, because array operations don't allocate new memory. The compiler (or runtime, because those are dynamic arrays) must complain here, but here it doesn't yet, and there's already a bug report on this.
 	{
 		double[] a = [1,1,1];
 		double[] b;
 		b.length = a.length;
 		b[] = a[] + 3;
 		assert(a == [1,1,1]);
 		assert(b == [4,4,4]); // Now it's fine
 	}
This is fine because in D the length attribute can also be written, this changes the array length, so there's space for the data to be written.
 	{
 		double[3] a = [1,1,1];
 		double[3] b = a[] + 3; // works although lvalue isn't a slice. Static 
 arrays? Because it's an initial value?
 		assert(a == [1,1,1]);
 		assert(b == [4,4,4]);
 	}
This works because of another bug in the compiler (it accepts some array ops even without the []), I have written a bug report on this lot of time ago. Walter has said this bug will be fixed.
 	{
 		double[3] a = [1,1,1];
 		auto b = a;
 		b = a[] + 3; // And so does this.. Something to do with static arrays?
 		assert(a == [1,1,1]);
 		assert(b == [4,4,4]);
 	}
Same compiler bug as above, that allows such sloppiness. Also b is a static array so the operation "auto b = a;" copies 3 values on the stack, so this is partially correct code.
 	{ // Like the previous example, but with dynamic arrays..
 		double[] a = [1,1,1];
 		auto b = a;
 		assert(a is b);
 		b = a[] + 3;
 		assert(a == [1,1,1]);
 		//writeln(b); // access violation. Because of dynamic arrays?
 	}	
I don't know, seems a bit messy. I will add it to bugzilla, despite it's partially wrong code.
 	{ // Like above, but using slicing like the spec says.. Works fine
 		double[] a = [1,1,1];
 		auto b = a;
 		assert(a is b);
 		writeln(typeof(b).stringof); // double[]
 		b[] = a[] + 3;
 		assert(a == [4,4,4]); // a also changed. I expected this
 		assert(b == [4,4,4]);
 	}
This is OK.
 	{
 		double[3] a = [1,1,1];
 		auto b = a[] + 3; // What happens here?
 		writeln(typeof(b).stringof); // double[]
 		assert(b.length == 3);
 		assert(b.capacity == 0);
 		//writeln(b); // access violation
 	}
In the second line you take a full slice of a static array, in practice defining a dynamic array with the same contents (no data copy). The code is wrong because in the second line there is no []. The runtime is buggy because the second line assigns to an empty array. I guess I have to add this too to bugzilla, plus another case.
 	{ // Same as above?
 		double[3] a = [1,1,1];
 		//writeln(a[] + 3); // access violation
 	}
This is not allowed by the current design of array operations. I'd like the compiler to catch this erroneus usage at compile time. I think I have put this in bugzilla lot of time ago. Bye, bearophile
Aug 08 2010
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Don:
 That is bug 4578, which has been fixed, and will be in the next compiler
release.
Good, there is no need to file it then. simendsjo post shows two more cases, this is the first:
 	{
 		double[3] a = [1,1,1];
 		auto b = a[] + 3; // What happens here?
 		writeln(typeof(b).stringof); // double[]
 		assert(b.length == 3);
 		assert(b.capacity == 0);
 		//writeln(b); // access violation
 	}
The runtime has to catch the assignment bug in the line annotated with "What happens here?". I think there is already a bug in bugzilla for this so I will not add it.
 	{ // Same as above?
 		double[3] a = [1,1,1];
 		//writeln(a[] + 3); // access violation
 	}
I don't remember if this case is already in bugzilla, and I don't know if the compiler can catch it. I add it to bug 3817 because I am not sure. Bye, bearophile
Aug 08 2010
prev sibling parent simendsjo <simen.endsjo pandavre.com> writes:
On 07.08.2010 14:10, simendsjo wrote:
 I'm new to D2, so please.. :)
(...) Thanks for all answers. Seems array operations is a bit buggy, so I'll rather look more into them at a later date.
Aug 08 2010