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