View mode: basic / threaded / horizontal-split · Log in · Help
April 18, 2012
Cast Object - get null
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?
April 18, 2012
Re: Cast Object - get null
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
April 18, 2012
Re: Cast Object - get null
> 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?
April 18, 2012
Re: Cast Object - get null
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
April 18, 2012
Re: Cast Object - get null
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) {
April 18, 2012
Re: Cast Object - get null
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)
April 18, 2012
Re: Cast Object - get null
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
April 18, 2012
Re: Cast Object - get null
> 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
April 18, 2012
Re: Cast Object - get null
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.
April 18, 2012
Re: Cast Object - get null
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
« First   ‹ Prev
1 2 3 4
Top | Discussion index | About this forum | D home