April 18, 2012
On Wednesday, April 18, 2012 20:02:32 Namespace wrote:
> > 1. opCast doesn't do an implict cast. You'll have to cast to get == to work.
> > 
> > 2. If you really have a static opCall, then the new isn't necessary.
> > 
> > 3. You need to return from opCast. You're just declaring a local variable.
> > 
> > 4. You need to import std.traits, or using Unqual will cause
> > the template
> > constraint to fail.
> > 
> > - Jonathan M Davis
> 
> 1. What have i to cast explicit? I thought that does the overloaded opEquals for me?

Since you're dealing with classes, it might work, since it takes Object. But then your opEquals is going to have to be able to cast to the appropriate type internally. If they were structs, it definitely wouldn't work, and in general, you're going to have to cast explictly when you want to convert something. Implicit conversions are relatively rare in D, which can be annoying at times, but it also reduces bugs. opCast is for explicit uses of cast(T) and does not do implicit conversions.

To do implicit conversions, you'd need to use alias this, but that wouldn't help you in this case, because you can currently only have one alias this per type (though you should be able to have multiple eventually), and even if you could have multiple, you'd need to declare one for every implicit conversion, which would be problematic with a templated type like you're dealing with (feasible, but definitely verbose).

> 2. See my post above.
> 3. I return with "return U(this.x, this.y);" that is not a local
> variable, imo.

Your latest example was

U opCast(U)() const
 if (is(Unqual!U == Vector2D!byte) ||
 is(Unqual!U == Vector2D!ubyte) ||
 is(Unqual!U == Vector2D!short) ||
 is(Unqual!U == Vector2D!ushort) ||
 is(Unqual!U == Vector2D!int) ||
 is(Unqual!U == Vector2D!uint) ||
 is(Unqual!U == Vector2D!long) ||
 is(Unqual!U == Vector2D!ulong) ||
 is(Unqual!U == Vector2D!float) ||
 is(Unqual!U == Vector2D!double) ||
 is(Unqual!U == Vector2D!real))
 {
 U v = new U(this.x, this.y);
 }

There's no return there.

> 4. Of course i import it, but it is implicit import if i import std.stdio.

No, it doesn't. If it does, it's an import bug. std.stdio does not publicly import std.traits. You need to import it.

- Jonathan M Davis
April 18, 2012
>
>> 4. Of course i import it, but it is implicit import if i import
>> std.stdio.
>
> No, it doesn't. If it does, it's an import bug. std.stdio does not publicly
> import std.traits. You need to import it.
>
> - Jonathan M Davis

Believe me, it works fine. So it must be a bug.

For opCast i have now this solution

	U opCast(U)() const {
		static if (is(FieldTypeTuple!(U)[0] == short)) {
			return Vector2D!(short)(this.x, this.y);
		}
		
		static if (is(FieldTypeTuple!(U)[0] == float)) {
			return Vector2D!(float)(this.x, this.y);
		}
		
		static if (is(FieldTypeTuple!(U)[0] == double)) {
			return Vector2D!(double)(this.x, this.y);
		}
		
		static if (is(FieldTypeTuple!(U)[0] == int)) {
			return Vector2D!(int)(this.x, this.y);
		}
		
		static if (is(FieldTypeTuple!(U)[0] == long)) {
			return Vector2D!(long)(this.x, this.y);
		}
		
		static if (is(FieldTypeTuple!(U)[0] == byte)) {
			return Vector2D!(byte)(this.x, this.y);
		}
		
		static if (is(FieldTypeTuple!(U)[0] == ushort)) {
			return Vector2D!(ushort)(this.x, this.y);
		}
		
		static if (is(FieldTypeTuple!(U)[0] == uint)) {
			return Vector2D!(uint)(this.x, this.y);
		}
		
		static if (is(FieldTypeTuple!(U)[0] == ulong)) {
			return Vector2D!(ulong)(this.x, this.y);
		}
		
		static if (is(FieldTypeTuple!(U)[0] == ubyte)) {
			return Vector2D!(ubyte)(this.x, this.y);
		}
		
		return null;
	}

which avoid explicit casts in opEquals.

So that work fine: if (vs2 == vf) {

Only two question: Is that correct behaviour and wouldn't change in future versions?
And exist a smarter solution as this? ;)

April 18, 2012
Too early happy, now it seems opEquals wouldn't be called...
I tried this again:

U opCast(U)() const if (is(Unqual!U == Vector2D!byte) ||
		is(Unqual!U == Vector2D!ubyte) ||
		is(Unqual!U == Vector2D!short) ||
		is(Unqual!U == Vector2D!ushort) ||
		is(Unqual!U == Vector2D!int) ||
		is(Unqual!U == Vector2D!uint) ||
		is(Unqual!U == Vector2D!long) ||
		is(Unqual!U == Vector2D!ulong) ||
		is(Unqual!U == Vector2D!float) ||
		is(Unqual!U == Vector2D!double) ||
		is(Unqual!U == Vector2D!real))
	{
		return U(this.x, this.y);
	}

And normal casts works perfectly but what should i do if i get Object like in opEquals?
I think you want me to say what I understand now slowly: it does not work with Object. Isn't it?
It's a very unhappy solution to call

if (vs == Vector2s(vf)) as simply if (vs == vf)

If there any other solutions or any ideas to fix my solution in my previous post?
April 18, 2012
On Thursday, April 19, 2012 00:49:29 Namespace wrote:
> Too early happy, now it seems opEquals wouldn't be called... I tried this again:
> 
> U opCast(U)() const if (is(Unqual!U == Vector2D!byte) ||
> is(Unqual!U == Vector2D!ubyte) ||
> is(Unqual!U == Vector2D!short) ||
> is(Unqual!U == Vector2D!ushort) ||
> is(Unqual!U == Vector2D!int) ||
> is(Unqual!U == Vector2D!uint) ||
> is(Unqual!U == Vector2D!long) ||
> is(Unqual!U == Vector2D!ulong) ||
> is(Unqual!U == Vector2D!float) ||
> is(Unqual!U == Vector2D!double) ||
> is(Unqual!U == Vector2D!real))
> {
> return U(this.x, this.y);
> }
> 
> And normal casts works perfectly but what should i do if i get
> Object like in opEquals?
> I think you want me to say what I understand now slowly: it does
> not work with Object. Isn't it?
> It's a very unhappy solution to call
> 
> if (vs == Vector2s(vf)) as simply if (vs == vf)
> 
> If there any other solutions or any ideas to fix my solution in my previous post?

It looks like you're dealing with an opCast bug - either http://d.puremagic.com/issues/show_bug.cgi?id=5747 or a variant of it.

If you declare another overload of opCast:

 Object opCast(T)() const
 if(is(Unqual!T == Object))
 {
 return this;
 }

then it should work.

I would also point out that it's really bizarre that you're using classes here. You definitely seem to be trying to treat them as value types and don't need polymorphism at all. So, I'd really advise using structs. However, if you did, then you definitely would have to use explict casts with opEquals, because it would require the exact type rather than Object. So, if you're insistent on not needing to cast, then structs aren't going to do what you want. But given that you're dealing with vectors of floats and ints which aren't implicitly convertible (or at least, float isn't implicitly convertible to int), it would make perfect sense to expect to have to cast them to compare them or have them do anything with each other, since that's what happens with the built-in types.

Also, there's no need to check for null in opEquals. == actually gets translated to this:

bool opEquals(Object lhs, Object rhs)
{
 // If aliased to the same object or both null => equal
 if (lhs is rhs) return true;

 // If either is null => non-equal
 if (lhs is null || rhs is null) return false;

 // If same exact type => one call to method opEquals
 if (typeid(lhs) is typeid(rhs) || typeid(lhs).opEquals(typeid(rhs)))
 return lhs.opEquals(rhs);

 // General case => symmetric calls to method opEquals
 return lhs.opEquals(rhs) && rhs.opEquals(lhs);
}

So, the issues of whether you're comparing an object against itself or where the object is null are taken care of for you. It also makes opEquals more correct by enforcing that it's equal in both directions when the types aren't the same.

- Jonathan M Davis
April 19, 2012
On Wednesday, April 18, 2012 19:43:07 Jonathan M Davis wrote:
> If you declare another overload of opCast:
> 
> Object opCast(T)() const
> if(is(Unqual!T == Object))
> {
> return this;
> }
> 
> then it should work.

Actually, this would be better:

 T opCast(T)()
 if(isImplicitlyConvertible!(typeof(this), T))
 {
 return this;
 }

 const(T) opCast(T)() const
 if(isImplicitlyConvertible!(typeof(this), const T))
 {
 return this;
 }

The other only works with Object and won't work with any other base classes if there are any. It also probably doesn't deal with const very well, and I'm surprised that it compiled. It seems like bug, since otherwise, it strips away const, which isn't good.

In either case, I believe that this version works and is more flexible. Ideally, it wouldn't be necessary though.

- Jonathan M Davis
April 19, 2012
Wow, many thanks for your trouble. Now it works as aspected.
I only need

T opCast(T)() const if(isImplicitlyConvertible!(typeof(this), T)) {
	return this;
}

to work.

But if i try to cast to a const like this
const Vector2s vs_ = cast(Vector2s)(vf);

I get a long list of compiler errors.
Thereby it's petty if i have only

T opCast(T)() const if(isImplicitlyConvertible!(typeof(this), T)) {
	return this;
}

or additional the const variant

const(T) opCast(T)() const if(isImplicitlyConvertible!(typeof(this), const T)) {
	return this;
}
April 19, 2012
On Thursday, April 19, 2012 08:25:13 Namespace wrote:
> Wow, many thanks for your trouble. Now it works as aspected. I only need
> 
> T opCast(T)() const if(isImplicitlyConvertible!(typeof(this), T))
> {
> 	return this;
> }
> 
> to work.
> 
> But if i try to cast to a const like this
> const Vector2s vs_ = cast(Vector2s)(vf);
> 
> I get a long list of compiler errors.
> Thereby it's petty if i have only
> 
> T opCast(T)() const if(isImplicitlyConvertible!(typeof(this), T))
> {
> 	return this;
> }
> 
> or additional the const variant
> 
> const(T) opCast(T)() const
> if(isImplicitlyConvertible!(typeof(this), const T)) {
> 	return this;
> }


Well, if the function is const (which makes this const), since you're returning this, the return type must be const. It can only return non-const if the function isn't const. That's why I suggested having both overloads.

- Jonathan M Davis
April 19, 2012
I must correct me: your solution works only with
if (vs2 == Vector2s(vf)) {
	writeln("equal");
}

but not with

if (vs2 == vf) {
	writeln("equal");
}
April 19, 2012
On Thursday, 19 April 2012 at 06:56:21 UTC, Jonathan M Davis wrote:
> On Thursday, April 19, 2012 08:25:13 Namespace wrote:
>> Wow, many thanks for your trouble. Now it works as aspected.
>> I only need
>> 
>> T opCast(T)() const if(isImplicitlyConvertible!(typeof(this), T))
>> {
>> 	return this;
>> }
>> 
>> to work.
>> 
>> But if i try to cast to a const like this
>> const Vector2s vs_ = cast(Vector2s)(vf);
>> 
>> I get a long list of compiler errors.
>> Thereby it's petty if i have only
>> 
>> T opCast(T)() const if(isImplicitlyConvertible!(typeof(this), T))
>> {
>> 	return this;
>> }
>> 
>> or additional the const variant
>> 
>> const(T) opCast(T)() const
>> if(isImplicitlyConvertible!(typeof(this), const T)) {
>> 	return this;
>> }
>
>
> Well, if the function is const (which makes this const), since you're
> returning this, the return type must be const. It can only return non-const if
> the function isn't const. That's why I suggested having both overloads.
>
> - Jonathan M Davis

Yeah, but
const Vector2s vs_ = cast(Vector2s)(vf);

don't work even with

U opCast(U)() const if (is(Unqual!U == Vector2D!byte) ||
	is(Unqual!U == Vector2D!ubyte) ||
	is(Unqual!U == Vector2D!short) ||
	is(Unqual!U == Vector2D!ushort) ||
	is(Unqual!U == Vector2D!int) ||
	is(Unqual!U == Vector2D!uint) ||
	is(Unqual!U == Vector2D!long) ||
	is(Unqual!U == Vector2D!ulong) ||
	is(Unqual!U == Vector2D!float) ||
	is(Unqual!U == Vector2D!double) ||
	is(Unqual!U == Vector2D!real))
{
	return U(this.x, this.y);
}

T opCast(T)() if(isImplicitlyConvertible!(typeof(this), T)) {
	return this;
}

const(T) opCast(T)() const if(isImplicitlyConvertible!(typeof(this), const T)) {
	return this;
}

April 19, 2012
On Thursday, April 19, 2012 09:01:15 Namespace wrote:
> Yeah, but
> const Vector2s vs_ = cast(Vector2s)(vf);
> 
> don't work even with

I don't know why it isn't working for you. It's working for me. You can look at the altered code here: http://codepad.org/C5Td5tVz

I had to comment out the lines with Summe though, since there's no such function in the code that you gave.

You should be able to compare the two versions with diff -w (assuming that you're on Linux - I don't know what the equivalent would be on Windows). But as far as I can tell based on your messages, what you have should work, so there's obviously a discrepancy or miscommunication somewhere.

- Jonathan M Davis