www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Cast Object - get null

reply "Namespace" <rswhite4 googlemail.com> writes:
override bool opEquals(Object o) const {
         if (o is null) {
		return false;
	}
	
	writeln(o); // write: cast.Vector2D!(float).Vector2D
	
	Vector2D!(T) vec = cast(Vector2D!(T)) o;
	
	writeln(vec); // write: null
         // ...

It seems the cast fail, but the question is: why?

Here my test context:

void main() {
	alias Vector2D!(short) Vector2s;
	alias Vector2D!(float) Vector2f;
	
	Vector2f vf = Vector2f(23, 42);
	
	Vector2s vs = Vector2s(vf);
	
	writefln("vs.x: %d, vs.y: %d", vs.x, vs.y);
	
	Vector2s vs2 = Vector2s(23, 42);
	
	if (vs2 == vf) {
		writeln("equal");
	}
}

Vector2D is my own class. If i compare vs2 with vs it works fine,
but if i compare vs or vs2 with vf, the cast fail and i get a
null-reference. How can i avoid this?
Apr 18 2012
next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Wednesday, April 18, 2012 18:58:42 Namespace wrote:
 override bool opEquals(Object o) const {
 if (o is null) {
 return false;
 }
 
 writeln(o); // write: cast.Vector2D!(float).Vector2D
 
 Vector2D!(T) vec = cast(Vector2D!(T)) o;
 
 writeln(vec); // write: null
 // ...
 
 It seems the cast fail, but the question is: why?
 
 Here my test context:
 
 void main() {
 alias Vector2D!(short) Vector2s;
 alias Vector2D!(float) Vector2f;
 
 Vector2f vf = Vector2f(23, 42);
 
 Vector2s vs = Vector2s(vf);
 
 writefln("vs.x: %d, vs.y: %d", vs.x, vs.y);
 
 Vector2s vs2 = Vector2s(23, 42);
 
 if (vs2 == vf) {
 writeln("equal");
 }
 }
 
 Vector2D is my own class. If i compare vs2 with vs it works fine,
 but if i compare vs or vs2 with vf, the cast fail and i get a
 null-reference. How can i avoid this?

Vector2s and Vector2f are completely unrelated types. Templated types have no relation to one another even if they're generated from the same template unless they have the same template arguments. If you have class Foo(T) { T value; } and you do auto a = new Foo!int; auto b = new Foo!float; it's like you copy and pasted to create two new classes: class FooInt { int value; } class FooFloat { float value; } and those classes aren't related at all. They could have a common base class (and do with Object) if you declared them that way class Foo(T) : Base { T value; } and then they could both be cast to the base type, but they can't be cast to each other, because neither is derived from the other. If you want to be able to cast your Vector2D!int and Vector2D!float types to one another, you're going to need to overload opCast. - Jonathan M Davis
Apr 18 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
 one another, you're going to need to overload opCast.

 - Jonathan M Davis

Thanks for your answer. I have tried to overload opCast in this way: U opCast(U)() const { return U(this.x, this.y); } But then i get this compiler error cast.d(36): Error: no property 'opCall' for type 'object.Object' cast.d(299): Error: template instance cast.Vector2D!(short).Vector2D.opCast!(Obj ect) error instantiating cast.d(36): Error: no property 'opCall' for type 'object.Object' cast.d(299): Error: template instance cast.Vector2D!(float).Vector2D.opCast!(Obj ect) error instantiating The dokumentation of opCast is very short, did i understand opCast wrong?
Apr 18 2012
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Wednesday, April 18, 2012 19:15:21 Namespace wrote:
 one another, you're going to need to overload opCast.
 
 - Jonathan M Davis

Thanks for your answer. I have tried to overload opCast in this way: U opCast(U)() const { return U(this.x, this.y); } But then i get this compiler error cast.d(36): Error: no property 'opCall' for type 'object.Object' cast.d(299): Error: template instance cast.Vector2D!(short).Vector2D.opCast!(Obj ect) error instantiating cast.d(36): Error: no property 'opCall' for type 'object.Object' cast.d(299): Error: template instance cast.Vector2D!(float).Vector2D.opCast!(Obj ect) error instantiating The dokumentation of opCast is very short, did i understand opCast wrong?

You're dealing with a class, so you need to use new. As it stands, you're trying to call an overload static opCall on U, and presumably, you haven't declared one. Ideally, you'd also have a template constraint restricting the cast to the types that you want to be able to cast to, but since you're dealing with a templated type, that can be a bit tricky. One (somewhat ugly) option would be to do something like 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 new U(x, y); } Another would be to have an enum on the type indicating that it's an instantiation of your Vector2D template (e.g. isVector2D). U opCast(U) const if(__traits(compiles, U.isVector2D)) { return new U(x, y); } - Jonathan M Davis
Apr 18 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
I take your first example and the relevant class part looks now 
like this:
class Vector2D(T) {
public:
	T x;
	T y;

	this() { }

	/**
	*
	*/
	static Vector2D!(T) opCall(U, V)(U x, V y) {
		Vector2D!(T) vec = new Vector2D!(T)();
		vec.x = cast(T) x;
		vec.y = cast(T) y;

		return vec;
	}
	
	/**
	*
	*/
	static Vector2D!(T) opCall(U)(const Vector2D!(U) vec) {
		assert(vec !is null);

		return Vector2D!(T)(vec.x, vec.y);
	}
	
	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);
	}

As you see i have a static opCall.
But now i get this compiler errors:
cast.d(309): Error: template instance opCast!(Object) 
opCast!(Object) does not m
atch template declaration opCast(U) if (is(Unqual!(U) == 
Vector2D!(byte)) || is(
Unqual!(U) == Vector2D!(ubyte)) || is(Unqual!(U) == 
Vector2D!(short)) || is(Unqu
al!(U) == Vector2D!(ushort)) || is(Unqual!(U) == Vector2D!(int)) 
|| is(Unqual!(U
) == Vector2D!(uint)) || is(Unqual!(U) == Vector2D!(long)) || 
is(Unqual!(U) == V
ector2D!(ulong)) || is(Unqual!(U) == Vector2D!(float)) || 
is(Unqual!(U) == Vecto
r2D!(double)) || is(Unqual!(U) == Vector2D!(real)))
cast.d(309): Error: function expected before (), not 
vs2.opCast!(Object) of type
  void
cast.d(309): Error: template instance opCast!(Object) 
opCast!(Object) does not m
atch template declaration opCast(U) if (is(Unqual!(U) == 
Vector2D!(byte)) || is(
Unqual!(U) == Vector2D!(ubyte)) || is(Unqual!(U) == 
Vector2D!(short)) || is(Unqu
al!(U) == Vector2D!(ushort)) || is(Unqual!(U) == Vector2D!(int)) 
|| is(Unqual!(U
) == Vector2D!(uint)) || is(Unqual!(U) == Vector2D!(long)) || 
is(Unqual!(U) == V
ector2D!(ulong)) || is(Unqual!(U) == Vector2D!(float)) || 
is(Unqual!(U) == Vecto
r2D!(double)) || is(Unqual!(U) == Vector2D!(real)))
cast.d(309): Error: function expected before (), not 
vf.opCast!(Object) of type
void

It seems that opCast and opEquals don't like each other.
Line 309 is
if (vs2 == vf) {
Apr 18 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
Sorry, "U v = new U(this.x, this.y);" means "U v = U(this.x, 
this.y);"
I tested it with static opCall and also with a normal constructor 
this(T x, T y)
Apr 18 2012
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Wednesday, April 18, 2012 19:37:25 Namespace wrote:
 I take your first example and the relevant class part looks now
 like this:
 class Vector2D(T) {
 public:
 T x;
 T y;
 
 this() { }
 
 /**
 *
 */
 static Vector2D!(T) opCall(U, V)(U x, V y) {
 Vector2D!(T) vec = new Vector2D!(T)();
 vec.x = cast(T) x;
 vec.y = cast(T) y;
 
 return vec;
 }
 
 /**
 *
 */
 static Vector2D!(T) opCall(U)(const Vector2D!(U) vec) {
 assert(vec !is null);
 
 return Vector2D!(T)(vec.x, vec.y);
 }
 
 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);
 }
 
 As you see i have a static opCall.
 But now i get this compiler errors:
 cast.d(309): Error: template instance opCast!(Object)
 opCast!(Object) does not m
 atch template declaration opCast(U) if (is(Unqual!(U) ==
 Vector2D!(byte)) || is(
 Unqual!(U) == Vector2D!(ubyte)) || is(Unqual!(U) ==
 Vector2D!(short)) || is(Unqu
 al!(U) == Vector2D!(ushort)) || is(Unqual!(U) == Vector2D!(int))
 
 || is(Unqual!(U
 
 ) == Vector2D!(uint)) || is(Unqual!(U) == Vector2D!(long)) ||
 is(Unqual!(U) == V
 ector2D!(ulong)) || is(Unqual!(U) == Vector2D!(float)) ||
 is(Unqual!(U) == Vecto
 r2D!(double)) || is(Unqual!(U) == Vector2D!(real)))
 cast.d(309): Error: function expected before (), not
 vs2.opCast!(Object) of type
 void
 cast.d(309): Error: template instance opCast!(Object)
 opCast!(Object) does not m
 atch template declaration opCast(U) if (is(Unqual!(U) ==
 Vector2D!(byte)) || is(
 Unqual!(U) == Vector2D!(ubyte)) || is(Unqual!(U) ==
 Vector2D!(short)) || is(Unqu
 al!(U) == Vector2D!(ushort)) || is(Unqual!(U) == Vector2D!(int))
 
 || is(Unqual!(U
 
 ) == Vector2D!(uint)) || is(Unqual!(U) == Vector2D!(long)) ||
 is(Unqual!(U) == V
 ector2D!(ulong)) || is(Unqual!(U) == Vector2D!(float)) ||
 is(Unqual!(U) == Vecto
 r2D!(double)) || is(Unqual!(U) == Vector2D!(real)))
 cast.d(309): Error: function expected before (), not
 vf.opCast!(Object) of type
 void
 
 It seems that opCast and opEquals don't like each other.
 Line 309 is
 if (vs2 == vf) {

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
Apr 18 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
 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? 2. See my post above. 3. I return with "return U(this.x, this.y);" that is not a local variable, imo. 4. Of course i import it, but it is implicit import if i import std.stdio. Here my total sourc eto avoid misconceptions: http://codepad.org/fnkyysYu
Apr 18 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
I see i must write

if (vs2 == cast(Vector2s)(vf)) {
	writeln("equal");
}

That is unacceptable. Is this the only possibility?
I thought that opEquals can cast this intern. It would seem that 
D code isn't so brief as i thought and hoped before.
Apr 18 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
On Wednesday, 18 April 2012 at 19:18:42 UTC, Namespace wrote:
 I see i must write

 if (vs2 == cast(Vector2s)(vf)) {
 	writeln("equal");
 }

 That is unacceptable. Is this the only possibility?
 I thought that opEquals can cast this intern. It would seem 
 that D code isn't so brief as i thought and hoped before.

I was wrong, event with if (vs2 == cast(Vector2s)(vf)) { it doesn't work. I get still this compiler error: cast.d(308): Error: template instance opCast!(Object) opCast!(Object) does not m atch template declaration opCast(U) if (is(Unqual!(U) == Vector2D!(byte)) || is( Unqual!(U) == Vector2D!(ubyte)) || is(Unqual!(U) == Vector2D!(short)) || is(Unqu al!(U) == Vector2D!(ushort)) || is(Unqual!(U) == Vector2D!(int)) || is(Unqual!(U ) == Vector2D!(uint)) || is(Unqual!(U) == Vector2D!(long)) || is(Unqual!(U) == V ector2D!(ulong)) || is(Unqual!(U) == Vector2D!(float)) || is(Unqual!(U) == Vecto r2D!(double)) || is(Unqual!(U) == Vector2D!(real))) cast.d(308): Error: function expected before (), not vs2.opCast!(Object) of type void cast.d(308): Error: template instance opCast!(Object) opCast!(Object) does not m atch template declaration opCast(U) if (is(Unqual!(U) == Vector2D!(byte)) || is( Unqual!(U) == Vector2D!(ubyte)) || is(Unqual!(U) == Vector2D!(short)) || is(Unqu al!(U) == Vector2D!(ushort)) || is(Unqual!(U) == Vector2D!(int)) || is(Unqual!(U ) == Vector2D!(uint)) || is(Unqual!(U) == Vector2D!(long)) || is(Unqual!(U) == V ector2D!(ulong)) || is(Unqual!(U) == Vector2D!(float)) || is(Unqual!(U) == Vecto r2D!(double)) || is(Unqual!(U) == Vector2D!(real))) cast.d(308): Error: function expected before (), not vf.opCast().opCast!(Object) of type void
Apr 18 2012
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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
Apr 18 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
 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? ;)
Apr 18 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
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?
Apr 18 2012
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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
Apr 18 2012
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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
Apr 18 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
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;
}
Apr 18 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
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
Apr 18 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
I must correct me: your solution works only with
if (vs2 == Vector2s(vf)) {
	writeln("equal");
}

but not with

if (vs2 == vf) {
	writeln("equal");
}
Apr 18 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
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; }
Apr 19 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
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
Apr 19 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
And which version do you use? I use DMD 2.059 on Windows 7.

I get this compile error with your code
object.Error: Access Violation
----------------
41943C
4192C7
40F75B
40BE90
40BECA
40BAEB
4206E1

If i comment out this part

     if (vs2 == vf) {
         writeln("equal");
     }


it works fine.
Apr 19 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, April 19, 2012 10:48:45 Namespace wrote:
 And which version do you use? I use DMD 2.059 on Windows 7.
 
 I get this compile error with your code
 object.Error: Access Violation
 ----------------
 41943C
 4192C7
 40F75B
 40BE90
 40BECA
 40BAEB
 4206E1
 
 If i comment out this part
 
      if (vs2 == vf) {
          writeln("equal");
      }
 
 
 it works fine.

I tried both 2.058 and the latest from github. But I'm on 64-bit Linux, so it's possible that you're seeing a Windows-specific issue. - Jonathan M Davis
Apr 19 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 19 April 2012 at 09:05:13 UTC, Jonathan M Davis 
wrote:
 On Thursday, April 19, 2012 10:48:45 Namespace wrote:
 And which version do you use? I use DMD 2.059 on Windows 7.
 
 I get this compile error with your code
 object.Error: Access Violation
 ----------------
 41943C
 4192C7
 40F75B
 40BE90
 40BECA
 40BAEB
 4206E1
 
 If i comment out this part
 
      if (vs2 == vf) {
          writeln("equal");
      }
 
 
 it works fine.

I tried both 2.058 and the latest from github. But I'm on 64-bit Linux, so it's possible that you're seeing a Windows-specific issue. - Jonathan M Davis

A specific Windows bug with opEquals and opCast? My Windows is 64 bit also. Can anyone reproduce this behaviour with Windows? I will download dmd later again to check if i have an older version or beta.
Apr 19 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
 I will download dmd later again to check if i have an older 
 version or beta.

After download dmd again it get still the same compile error.
Apr 19 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, April 19, 2012 11:15:23 Namespace wrote:
 A specific Windows bug with opEquals and opCast?

Maybe. Certainly, it's working on my Linux box, so if you're compiling the same code that I am, and you're using 2.059, it definitely sounds like it's a Windows-specific bug.
 My Windows is 64 bit also.

The fact that it's 64-bit shouldn't matter on Windows, because dmd can't generate 64-bit code on Windows yet. - Jonathan M Davis
Apr 19 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 19 April 2012 at 09:22:24 UTC, Jonathan M Davis 
wrote:
 On Thursday, April 19, 2012 11:15:23 Namespace wrote:
 A specific Windows bug with opEquals and opCast?

Maybe. Certainly, it's working on my Linux box, so if you're compiling the same code that I am, and you're using 2.059, it definitely sounds like it's a Windows-specific bug.
 My Windows is 64 bit also.

The fact that it's 64-bit shouldn't matter on Windows, because dmd can't generate 64-bit code on Windows yet. - Jonathan M Davis

Ok. And what schould i do now? Any patches available for that? Otherwise i must cast up to dmd 2.060 explicit as you do in the first if condition.
Apr 19 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, April 19, 2012 11:27:20 Namespace wrote:
 On Thursday, 19 April 2012 at 09:22:24 UTC, Jonathan M Davis
 
 wrote:
 On Thursday, April 19, 2012 11:15:23 Namespace wrote:
 A specific Windows bug with opEquals and opCast?

Maybe. Certainly, it's working on my Linux box, so if you're compiling the same code that I am, and you're using 2.059, it definitely sounds like it's a Windows-specific bug.
 My Windows is 64 bit also.

The fact that it's 64-bit shouldn't matter on Windows, because dmd can't generate 64-bit code on Windows yet. - Jonathan M Davis

Ok. And what schould i do now? Any patches available for that? Otherwise i must cast up to dmd 2.060 explicit as you do in the first if condition.

Actually, I just re-ran the code on my box, and it does segfault. Either I forgot to run it or I didn't notice the segfault, since it isn't as obvious on Linux with all of the other output: vs.x: 23, vs.y: 42 raw.Vector2D!(short).Vector2D raw.Vector2D!(short).Vector2D equal raw.Vector2D!(float).Vector2D null Segmentation fault What's going wrong is that this cast in opEquals: Vector2D!(T) vec = cast(Vector2D!(T)) o; is failing. The result is null. That's what you'd expect if the built-in cast is being used rather than opCast. And if I put print statements in all three of the opCasts, none of them are called. Upon thinking further about it, I believe that the problem is that you're casting from _Object_ rather than one of the other instantiations of Vector2D, and Object obviously doesn't define an opCast for your type. So, it uses the normal, built-in cast, and it fails, because the type that you're attempting to cast to is not derived from the one that you're trying to cast to. If you could get it to its actual type and _then_ cast it, you could do it. But that's a rather nasty problem. After messing with it a bit though, I do believe that I've come up with a solution. Change opEquals to this: override bool opEquals(Object o) const { writeln(o); auto vec = castFromObject(o); assert(vec !is null); writeln(vec); return vec.x == this.x && vec.y == this.y; } private static Vector2D castFromObject(Object o) { import std.typetuple; foreach(U; TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong, float, double, real)) { if(auto vec = cast(Vector2D!U)o) return cast(Vector2D)vec; } return null; } I believe that that takes care of the problem. By the way, inside of a template, you don't need to reuse the template arguments when refering to it. So, inside of Vector2D, you can use Vector2D instead of Vector2D!T. - Jonathan M Davis
Apr 19 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
A great thanks to you. But any of my tries to make
"const Vector2D vec = castFromObject(o);" possible i get an 
error. Didn't i must only write "private static const(Vector2D) 
castFromObject(Object o)" instead of "private static Vector2D 
castFromObject(Object o)"?
Apr 19 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
It seems that i can't cast if i want a const Vector2D, neither 
with castFromtObject nor with opCast. If i do it i get a very 
long list of compile errors. It's no problem because i can deal 
without cast to const but it would be usefull if you can show me 
how i can use both, const and normal casts.
Apr 19 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
On Thursday, 19 April 2012 at 15:48:29 UTC, Namespace wrote:
 It seems that i can't cast if i want a const Vector2D, neither 
 with castFromtObject nor with opCast. If i do it i get a very 
 long list of compile errors. It's no problem because i can deal 
 without cast to const but it would be usefull if you can show 
 me how i can use both, const and normal casts.

For example in this case void foo(T)(const Vector2D!(T) vec) { bar(cast(Vector2s) vec); } void bar(const Vector2s vec) { } const Vector2f vf = Vector2f(23, 42); Vector2s vs = Vector2s(vf); Vector2s vs_ = cast(Vector2s) vf; Vector2f vf_ = cast(Vector2f) vs; Vector2s vs2 = Vector2s(23, 42); if (vs2 == vf) { writeln("equal!"); } foo(vf); foo(vs); i get this compiler errors: cast.d(323): Error: template cast.Vector2D!(short).Vector2D.opCast matches more than one template declaration, cast.d(285):opCast(U) if (is(Unqual!(U) == Vector 2D!(byte)) || is(Unqual!(U) == Vector2D!(ubyte)) || is(Unqual!(U) == Vector2D!(s hort)) || is(Unqual!(U) == Vector2D!(ushort)) || is(Unqual!(U) == Vector2D!(int) ) || is(Unqual!(U) == Vector2D!(uint)) || is(Unqual!(U) == Vector2D!(long)) || i s(Unqual!(U) == Vector2D!(ulong)) || is(Unqual!(U) == Vector2D!(float)) || is(Un qual!(U) == Vector2D!(double)) || is(Unqual!(U) == Vector2D!(real))) and cast.d( 306):opCast(T) if (isImplicitlyConvertible!(typeof(this),const(T))) cast.d(360): Error: template instance cast.foo!(short) error instantiating I can avoid them if i change bar to void foo(T)(const Vector2D!(T) vec) { static if (is(typeof(vec.x) == const float)) { bar(cast(Vector2s) vec); } else { bar(vec); } } Of course i must check for more then only "const float" but it is only a test case. So it seems i have to change the cast operator. But i have no idea how. I thougth that "inout" would help me, but i was wrong. So maybe you have some ideas?
Apr 19 2012
prev sibling next sibling parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Wednesday, 18 April 2012 at 17:28:16 UTC, Jonathan M Davis 
wrote:
 Ideally, you'd also have a template constraint restricting the 
 cast to the
 types that you want to be able to cast to, but since you're 
 dealing with a
 templated type, that can be a bit tricky. One (somewhat ugly) 
 option would be
 to do something like

 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 new U(x, y);
 }

 Another would be to have an enum on the type indicating that 
 it's an
 instantiation of your Vector2D template (e.g. isVector2D).

 U opCast(U) const
  if(__traits(compiles, U.isVector2D))
 {
  return new U(x, y);
 }

 - Jonathan M Davis

T opCast(T : const(Vector2D!U), U)() const { return new T(x, y); }
Apr 19 2012
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
 T opCast(T : const(Vector2D!U), U)() const
 {
     return new T(x, y);
 }

Awesome, now i only need this three and it works perfect. typeof(this) opCast(T)() if (isImplicitlyConvertible!(typeof(this), T)) { writeln("implicit cast"); return this; } const(typeof(this)) opCast(T)() const if (isImplicitlyConvertible!(typeof(this), const T)) { writeln("implicit const cast"); return this; } T opCast(T : const(Vector2D!(U)), U)() const { writeln("Other cast"); return T(x, y); } Many thanks to you two! :)
Apr 19 2012
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Thursday, April 19, 2012 23:06:58 Jakob Ovrum wrote:
 T opCast(T : const(Vector2D!U), U)() const
 {
 return new T(x, y);
 }

Cool. That's definitely better. I definitely need to improve my template-foo with regards to :. - Jonathan M Davis
Apr 19 2012