Operators overloading

Jonathan M Davis jmdavisProg at gmx.com
Sun May 19 02:03:20 PDT 2013


On Sunday, May 19, 2013 09:32:09 matovitch wrote:
> Hello from France everyone ! (I hope my english will be
> readable...)
> 
> Yesterday, I discover D and that was really really great. I am
> far from being a guru (it seems there are a lot here ;-) but I
> foud the language clear and expressive the documentation is very
> well done futhermore dmd is incredibly fast and the logs are pure
> awesomness (a gcc command often doesn't fit on my shell). I know
> you are waiting for a 'but' and there is one : it's about
> operators overloading. First, but that kind of ok with me, I
> don't like the syntax :
> 
> 	const Vertex opBinary(string op)(const ref Vertex vertex)
> 		if (op == "+" || op == "-")
> 	{
> 		Vertex result = *this;
> 		mixin("result" ~ op ~ "= vertex;");
> 		return result;
> 	}
> 
> I don't like the 'if' outside and the condition could be really
> long : if (op == "+" || op == "-" || op == "*" || op == "/").
> Okay, putting the if inside is quite easy :
> 
> 	const Vertex opBinary(string op)(const ref Vertex vertex)
> 	{
> 		static if 	if (op == "+" || op == "-")
> 		{
> 			Vertex result = *this;
> 			mixin("result" ~ op ~ "= vertex;");
> 			return result;
> 		}
> 	}
> 
> But...I'd like to define cross product :
> 
> 	const T opBinary(string op)(const ref Vertex vertex)
> 	{
> 		static if (op == "*")
> 		{
> 			T result = 0;
> 			foreach(i; 0..vertex_size)
> 				result += coordinate[i] * vertex.coordinate[i];
> 			return result;
> 		}
> 	}
> 
> The compiler is not so great here and doesn't distinguish the two
> opBinary by their signatures. Why ? Before looking at the
> documentation again I tried something like that :
> 
> 	const Vertex opBinary(string op : ["+", "-"])(const ref Vertex
> vertex)
> 	{
> 		{
> 			Vertex result = *this;
> 			mixin("result" ~ op ~ "= vertex;");
> 			return result;
> 		}
> 	}
> 
> 	const T opBinary(string op : "*")(const ref Vertex vertex)
> 	{
> 
> 		T result = 0;
> 		foreach(i; 0..vertex_size)
> 			result += coordinate[i] * vertex.coordinate[i];
> 		return result;
> 	}
> 
> The second one is okay, but the fisrt one isn't correct. I think
> this kind of template specialization over a list could be great
> with mixins and static if/switch. What do you think ? May be
> there is an other way to do what I want...

If you want to distinguish between overloads of templated functions based on 
template parameters, template constraints are the correct way to do it. 
Nothing inside of the function - including static ifs - is considered in 
overloading. By the time the compiler even looks at that code, the overload 
has already been decided (or determined to be ambiguous). And what you can do 
directly in the template parameters to distinguish them - e.g. string op : "+" 
- is extremely limited. Much as you may not like it, the correct way to handle 
this is with template constraints. That's what they're for.

Now, there are ways to reduce their length - particularly if you're testing 
the same thing often. In that case, you could make an eponymous template for 
the test.

template isAddOrSub(string op)
{
    enum isAddOrSub = op == "+" || op == "-";
}

Then you can do

const Vertex opBinary(string op)(const ref Vertex vertex)
    if (isAddOrSub!op)
{...}

Now, in this particular case, I wouldn't think that it would be worth it. 
Which operators you need to use with a particular overload varies too much 
from type to type for an eponymous template like that to make much sense.

Another alternative would be to use a function like std.algorithm.equal except 
that it tested that one of the arguments was equal to the first one rather than 
just testing one argument against it. Something like

const Vertex opBinary(string op)(const ref Vertex vertex)
    if (isOneOf(op, "+", "-"))
{...}

Off the top of my head, I'm not aware of a function like that in the standard 
library, but I may just not being think of it, and it probably wouldn't be all 
that hard to write, at least if efficiency wasn't a major concern.

In general though, AFAIK, most people just do

const Vertex opBinary(string op)(const ref Vertex vertex)
    if (op == "+" || op == "-")
{...}

and don't have a problem with it.

- Jonathan M Davis


More information about the Digitalmars-d mailing list