www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Can i rewrite methods in one line?

reply "Ivan Agafonov" <armadil yandex.ru> writes:
struct Vector(T, uint size)
{
	static assert(size >= 2 && size <= 4);
	static assert(__traits(isFloating, T);
	
	/// Vector components
	union
	{
		T[size] array = 0;
		struct
		{
			static if(size == 1) T x;
			static if(size == 2) T x, y;
			static if(size == 3) T x, y, z;
			static if(size == 4) T x, y, z, w;
		}
	}

	this (T rhs)			{ array[] = rhs; }
	this (T[] components...)	{ array[] = components[]; }
	this (T* components)		{ array[] = components[0..size]; }
	this (T[size] components)	{ array[] = components[]; }
	this (Vector rhs)		{ array[] = rhs.array[]; }
	
	Vector opUnary(string op) () if (op == "-")
	{
		Vector tmp;
		tmp.array[] = -array[];
		return tmp;
	}

	Vector opBinary(string op) (Vector rhs)
		if(op == "+" || op == "-" || op == "*" || op == "/")
	{
		Vector tmp;
		tmp.array[] = mixin("array[] "~op~" rhs.array[]");
		return tmp;
	}
	
	Vector opBinary(string op) (T rhs)
		if(op == "+" || op == "-" || op == "*" || op == "/")
	{
		Vector tmp;
		tmp.array[] = mixin("array[] "~op~" rhs");
		return tmp;
	}

	ref Vector opOpAssign(string op) (Vector rhs)
		if(op == "+" || op == "-" || op == "*" || op == "/")
	{
		mixin("array[] "~op~"= rhs.array[];");
		return this;
	}

	ref Vector opOpAssign(string op) (T rhs)
		if(op == "+" || op == "-" || op == "*" || op == "/")
	{
		mixin("array[] "~op~"= rhs;");
		return this;
	}
}

I want to rewrite it in something like this:

struct Vector(T, uint size)
{
	static assert(size >= 2 && size <= 4);
	static assert(__traits(isFloating, T);
	
	/// Vector components
	union
	{
		T[size] array = 0;
		struct
		{
			static if(size == 1) T x;
			static if(size == 2) T x, y;
			static if(size == 3) T x, y, z;
			static if(size == 4) T x, y, z, w;
		}
	}

	this (T rhs)			{ array[] = rhs; }
	this (T[] components...)	{ array[] = components[]; }
	this (T* components)		{ array[] = components[0..size]; }
	this (T[size] components)	{ array[] = components[]; }
	this (Vector rhs)		{ array[] = rhs.array[]; }
	
	Vector opUnary(string op) () if (op == "-")
	{ return Vector(-array); }

	Vector opBinary(string op) (Vector rhs)
		if(op == "+" || op == "-" || op == "*" || op == "/")
	{ return Vector(mixin("array[] "~op~" rhs.array[]")); }
	
	Vector opBinary(string op) (T rhs)
		if(op == "+" || op == "-" || op == "*" || op == "/")
	{ return Vector(mixin("array[] "~op~" rhs")); }

	ref Vector opOpAssign(string op) (Vector rhs)
		if(op == "+" || op == "-" || op == "*" || op == "/")
	{ return Vector(mixin("array[] "~op~"= rhs.array[]")); }

	ref Vector opOpAssign(string op) (T rhs)
		if(op == "+" || op == "-" || op == "*" || op == "/")
	{ return Vector(mixin("array[] "~op~"= rhs")); }
}

Main goal is to return and constuct in one place. Can I do so?
I now that there will take place compiller optimisations and both 
versions will be the same, but what if not? PS: Sorry for my 
english.
Sep 02 2012
next sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
In general, yes, you can construct and return at the same time. As you 
said, in a language like D where source code is almost always visible, 
the compiler can apply many optimization techniques.

However, some of your operators ended up having semantic differences. 
opOpAssign used to return a reference to this object:

     ref Vector opOpAssign(string op) (Vector rhs)
         if(op == "+" || op == "-" || op == "*" || op == "/")
     {
         mixin("array[] "~op~"= rhs.array[];");
         return this;
     }

opOpAssign now returns a reference to a newly-created temporary object:

     ref Vector opOpAssign(string op) (Vector rhs)
         if(op == "+" || op == "-" || op == "*" || op == "/")
     { return Vector(mixin("array[] "~op~"= rhs.array[]")); }

(It is the same for the other opOpAssign.)

Ali
Sep 02 2012
parent reply "Ivan Agafonov" <armadil yandex.ru> writes:
On Monday, 3 September 2012 at 02:40:09 UTC, Ali Çehreli wrote:
 In general, yes, you can construct and return at the same time. 
 As you said, in a language like D where source code is almost 
 always visible, the compiler can apply many optimization 
 techniques.

 However, some of your operators ended up having semantic 
 differences. opOpAssign used to return a reference to this 
 object:

     ref Vector opOpAssign(string op) (Vector rhs)
         if(op == "+" || op == "-" || op == "*" || op == "/")
     {
         mixin("array[] "~op~"= rhs.array[];");
         return this;
     }

 opOpAssign now returns a reference to a newly-created temporary 
 object:

     ref Vector opOpAssign(string op) (Vector rhs)
         if(op == "+" || op == "-" || op == "*" || op == "/")
     { return Vector(mixin("array[] "~op~"= rhs.array[]")); }

 (It is the same for the other opOpAssign.)

 Ali
I made a mistake here. This operators have already "onelined" : ref Vector opAssign(Vector rhs) { array[] = rhs.array[]; return this; } ref Vector opAssign(T[size] rhs) { array[] = rhs[]; return this; } ref Vector opOpAssign(string op) (T[size] rhs) if(op == "+" || op == "-" || op == "*" || op == "/") { mixin("array[] "~op~"= rhs[];"); return this; } ref Vector opOpAssign(string op) (Vector rhs) if(op == "+" || op == "-" || op == "*" || op == "/") { mixin("array[] "~op~"= rhs.array[];"); return this; } ref Vector opOpAssign(string op) (T rhs) if(op == "+" || op == "-" || op == "*" || op == "/") { mixin("array[] "~op~"= rhs;"); return this; } But i can't write something like this: return Vector(mixin("array[] "~op~"= rhs.array[]")); because array[] op= rhs.array[] is not a right expression it does not return an array, it can only be used in assigment to slice like this[]. And expression array op= rhs.array does not make sense too.
Sep 02 2012
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 09/02/2012 07:57 PM, Ivan Agafonov wrote:

 ref Vector opOpAssign(string op) (T rhs) if(op == "+" || op == "-" || op
 == "*" || op == "/")
 { mixin("array[] "~op~"= rhs;"); return this; }

 But i can't write something like this:
 return Vector(mixin("array[] "~op~"= rhs.array[]"));
You meant it for opOpAssign, right? opOpAssign must 'return this', not a new object. Otherwise chaining operators would be confusing: (v0 += v1) *= v2; If the += operation could return a new object (which it can't), then *= would be operating on that. So your existing version is correct: ref Vector opOpAssign(string op) (T[size] rhs) if(op == "+" || op == "-" || op == "*" || op == "/") { mixin("array[] "~op~"= rhs[];"); return this; } But if you don't care about chained operations you can also return void: void opOpAssign(string op) (T[size] rhs) if(op == "+" || op == "-" || op == "*" || op == "/") { mixin("array[] "~op~"= rhs[];"); } Ali
Sep 02 2012
prev sibling parent reply "Ivan Agafonov" <armadil yandex.ru> writes:
Yeah! I did it!
How about this solution? What do you think?

static assert(size >= 2 && size <= 4);
	static assert(__traits(isFloating, T));
	
	/// Vector components
	union
	{
		T[size] array = 0;
		struct
		{
			static if(size == 2) T x, y;
			static if(size == 3) T x, y, z;
			static if(size == 4) T x, y, z, w;
		}
	}

	this (T rhs)			{ array[] = rhs; }
	this (T[] components...)	{ array[] = components[]; }
	this (T* components)		{ array[] = components[0..size]; }
	this (T[size] components)	{ array[] = components[]; }
	this (Vector rhs)		{ array[] = rhs.array[]; }
	
	private static bool isMathOp(string op)
	{ return (op == "+" || op == "-" || op == "*" || op == "/"); }
	
	Vector opUnary(string op) () if (op == "-")
	{ return Vector(array.dup[] = -array[]); }

	Vector opBinary(string op) (Vector rhs) if(isMathOp(op))
	{ return Vector(mixin("array.dup[] "~op~"= rhs.array[]")); }
	
	Vector opBinary(string op) (T rhs) if(isMathOp(op))
	{ return Vector(mixin("array.dup[] "~op~"= rhs")); }

	ref Vector opAssign(Vector rhs) { array[] = rhs.array[]; return 
this; }
	ref Vector opAssign(T[size] rhs) { array[] = rhs[]; return this; 
}
	
	ref Vector opOpAssign(string op) (T[size] rhs) if(isMathOp(op))
	{ mixin("array[] "~op~"= rhs[];"); return this; }
	
	ref Vector opOpAssign(string op) (Vector rhs) if(isMathOp(op))
	{ mixin("array[] "~op~"= rhs.array[];"); return this; }
	
	ref Vector opOpAssign(string op) (T rhs) if(isMathOp(op))
	{ mixin("array[] "~op~"= rhs;"); return this; }

	... Some other op's ...
}
Sep 02 2012
next sibling parent "Ivan Agafonov" <armadil yandex.ru> writes:
Note that opBinary operators uses op= instead of op :

Vector opBinary(string op) (Vector rhs) if(isMathOp(op))
{ return Vector(mixin("array.dup[] "~op~"= rhs.array[]")); }

Vector opBinary(string op) (T rhs) if(isMathOp(op))
{ return Vector(mixin("array.dup[] "~op~"= rhs")); }
Sep 02 2012
prev sibling parent "Ivan Agafonov" <armadil yandex.ru> writes:
Note that opBinary operators uses op= instead of op :

Vector opBinary(string op) (Vector rhs) if(isMathOp(op))
{ return Vector(mixin("array.dup[] "~op~"= rhs.array[]")); }

Vector opBinary(string op) (T rhs) if(isMathOp(op))
{ return Vector(mixin("array.dup[] "~op~"= rhs")); }
Sep 02 2012