digitalmars.D.learn - Cast Object - get null
- Namespace (32/32) Apr 18 2012 override bool opEquals(Object o) const {
- Jonathan M Davis (31/67) Apr 18 2012 Vector2s and Vector2f are completely unrelated types. Templated types ha...
- Namespace (16/18) Apr 18 2012 Thanks for your answer.
- Jonathan M Davis (31/53) Apr 18 2012 You're dealing with a class, so you need to use new. As it stands, you'r...
- Namespace (77/77) Apr 18 2012 I take your first example and the relevant class part looks now
- Namespace (4/4) Apr 18 2012 Sorry, "U v = new U(this.x, this.y);" means "U v = U(this.x,
- Jonathan M Davis (7/94) Apr 18 2012 1. opCast doesn't do an implict cast. You'll have to cast to get == to w...
- Namespace (9/19) Apr 18 2012 1. What have i to cast explicit? I thought that does the
- Namespace (7/7) Apr 18 2012 I see i must write
- Namespace (37/44) Apr 18 2012 I was wrong, event with
- Jonathan M Davis (34/56) Apr 18 2012 Since you're dealing with classes, it might work, since it takes Object....
- Namespace (50/56) Apr 18 2012 Believe me, it works fine. So it must be a bug.
- Namespace (24/24) Apr 18 2012 Too early happy, now it seems opEquals wouldn't be called...
- Jonathan M Davis (40/68) Apr 18 2012 It looks like you're dealing with an opCast bug - either
- Jonathan M Davis (19/28) Apr 18 2012 Actually, this would be better:
- Namespace (20/20) Apr 18 2012 Wow, many thanks for your trouble. Now it works as aspected.
- Jonathan M Davis (5/32) Apr 18 2012 Well, if the function is const (which makes this const), since you're
- Namespace (26/63) Apr 19 2012 Yeah, but
- Jonathan M Davis (10/14) Apr 19 2012 I don't know why it isn't working for you. It's working for me. You can ...
- Namespace (16/16) Apr 19 2012 And which version do you use? I use DMD 2.059 on Windows 7.
- Jonathan M Davis (4/25) Apr 19 2012 I tried both 2.058 and the latest from github. But I'm on 64-bit Linux, ...
- Namespace (7/33) Apr 19 2012 A specific Windows bug with opEquals and opCast? My Windows is 64
- Namespace (1/3) Apr 19 2012 After download dmd again it get still the same compile error.
- Jonathan M Davis (7/9) Apr 19 2012 Maybe. Certainly, it's working on my Linux box, so if you're compiling t...
- Namespace (5/17) Apr 19 2012 Ok. And what schould i do now? Any patches available for that?
- Jonathan M Davis (47/70) Apr 19 2012 Actually, I just re-ran the code on my box, and it does segfault. Either...
- Namespace (8/8) Apr 18 2012 I must correct me: your solution works only with
- Jakob Ovrum (6/37) Apr 19 2012 T opCast(T : const(Vector2D!U), U)() const
- Namespace (16/20) Apr 19 2012 Awesome, now i only need this three and it works perfect.
- Jonathan M Davis (4/8) Apr 19 2012 Cool. That's definitely better. I definitely need to improve my template...
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
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
one another, you're going to need to overload opCast. - Jonathan M DavisThanks 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
On Wednesday, April 18, 2012 19:15:21 Namespace wrote: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 Davisone another, you're going to need to overload opCast. - Jonathan M DavisThanks 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
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
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
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
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 Davis1. 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
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
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
On Wednesday, April 18, 2012 20:02:32 Namespace wrote: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).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 Davis1. 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.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
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? ;)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
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
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
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
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
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
On Thursday, 19 April 2012 at 06:56:21 UTC, Jonathan M Davis wrote:On Thursday, April 19, 2012 08:25:13 Namespace wrote: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; }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 19 2012
On Thursday, April 19, 2012 09:01:15 Namespace wrote:Yeah, but const Vector2s vs_ = cast(Vector2s)(vf); don't work even withI 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
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
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
On Thursday, 19 April 2012 at 09:05:13 UTC, Jonathan M Davis wrote:On Thursday, April 19, 2012 10:48:45 Namespace wrote: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.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
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
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
On Thursday, 19 April 2012 at 09:22:24 UTC, Jonathan M Davis wrote:On Thursday, April 19, 2012 11:15:23 Namespace wrote: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.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
On Thursday, April 19, 2012 11:27:20 Namespace wrote:On Thursday, 19 April 2012 at 09:22:24 UTC, Jonathan M Davis wrote: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 DavisOn Thursday, April 19, 2012 11:15:23 Namespace wrote: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.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
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
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
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
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
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 DavisT opCast(T : const(Vector2D!U), U)() const { return new T(x, y); }
Apr 19 2012
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
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