digitalmars.D.learn - Segfault when casting array of Interface types
- rcor (17/17) Sep 15 2014 I'm back for another round of "is this a bug, or am I doing
- Franz (13/30) Sep 15 2014 look at what 's auto has created:
- Franz (2/36) Sep 15 2014 i is a I[]
- rcor (8/10) Sep 15 2014 I expected i to be an I[], but shouldn't a casting an element of
- rcor (8/8) Sep 15 2014 seemingly even weirder:
- Klaus (10/51) Sep 15 2014 writing
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (5/57) Sep 16 2014 AFACIS there's nothing wrong with his use of casting. It's fine
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (15/19) Sep 16 2014 Correction:
- rcor (8/23) Sep 16 2014 Thanks, didn't think of trying std.conv.to. Can someone expand a
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (8/36) Sep 16 2014 Reinterpret cast means that the compiler should treat whatever is
- rcor (15/23) Sep 16 2014 I guess I could have checked that out myself:
- rcor (7/14) Sep 16 2014 Admittedly this came about as a result of some poor design on my
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (14/30) Sep 15 2014 I don't have an answer and I am not even sure whether this is a bug.
I'm back for another round of "is this a bug, or am I doing something stupid?". C and D implement interface I, and I have an array of each. I'd like to combine these into one I[], but eventually I'd like to cast an element back to its original type. interface I {} class C : I {} class D : I {} void main() { C[] c = [new C, new C]; D[] d = [new D, new D]; auto i = cast(I[]) c ~ cast(I[]) d; assert(cast(C) i[0]); // segfault } casting each array to I[] is fine, but casting an element back to C segfaults (even if it weren't a C, it should just return null, right?)
Sep 15 2014
On Tuesday, 16 September 2014 at 02:21:42 UTC, rcor wrote:I'm back for another round of "is this a bug, or am I doing something stupid?". C and D implement interface I, and I have an array of each. I'd like to combine these into one I[], but eventually I'd like to cast an element back to its original type. interface I {} class C : I {} class D : I {} void main() { C[] c = [new C, new C]; D[] d = [new D, new D]; auto i = cast(I[]) c ~ cast(I[]) d; assert(cast(C) i[0]); // segfault } casting each array to I[] is fine, but casting an element back to C segfaults (even if it weren't a C, it should just return null, right?)look at what 's auto has created: import std.stdio; interface I {} class C : I {} class D : I {} void main() { C[] c = [new C, new C]; D[] d = [new D, new D]; auto i = cast(I[]) c ~ cast(I[]) d; writeln(typeof(i).stringof); } Your issue comme from auto.
Sep 15 2014
On Tuesday, 16 September 2014 at 03:03:16 UTC, Franz wrote:On Tuesday, 16 September 2014 at 02:21:42 UTC, rcor wrote:i is a I[]I'm back for another round of "is this a bug, or am I doing something stupid?". C and D implement interface I, and I have an array of each. I'd like to combine these into one I[], but eventually I'd like to cast an element back to its original type. interface I {} class C : I {} class D : I {} void main() { C[] c = [new C, new C]; D[] d = [new D, new D]; auto i = cast(I[]) c ~ cast(I[]) d; assert(cast(C) i[0]); // segfault } casting each array to I[] is fine, but casting an element back to C segfaults (even if it weren't a C, it should just return null, right?)look at what 's auto has created: import std.stdio; interface I {} class C : I {} class D : I {} void main() { C[] c = [new C, new C]; D[] d = [new D, new D]; auto i = cast(I[]) c ~ cast(I[]) d; writeln(typeof(i).stringof); } Your issue comme from auto.
Sep 15 2014
On Tuesday, 16 September 2014 at 03:05:57 UTC, Franz wrote:I expected i to be an I[], but shouldn't a casting an element of an I[] to a C return either a C or null? It is if I do this: I[] i = [cast(I) new C, new D]; assert(cast(C) i[0]); // fine Come to think of it, the above will probably work in my situation. But I still wonder why the first example doesn't work.Your issue comme from auto.i is a I[]
Sep 15 2014
seemingly even weirder: I[] i0 = [new C, new C]; assert(cast(C) i0[0]); // fine C[] c = [new C, new C]; I[] i1 = cast(I[]) c; assert(cast(C) i1[0]); // fails It works when I create an I[] from a C[] literal, but not when I cast a previously declared C[] to an I[].
Sep 15 2014
On Tuesday, 16 September 2014 at 03:05:57 UTC, Franz wrote:On Tuesday, 16 September 2014 at 03:03:16 UTC, Franz wrote:writing auto i = cast(I[]) c ~ cast(I[]) d; is just a horrible way of shortcuting the static typing. You write this thinking that i "has to be..." and then you complain latter because the cast does not work. D is a strongly typed lang. in your example you use "auto" because your brain doesnt give you what the type of i has to be, which is an error. D is not a scripting lang. You made a wrong usage of "auto".On Tuesday, 16 September 2014 at 02:21:42 UTC, rcor wrote:i is a I[]I'm back for another round of "is this a bug, or am I doing something stupid?". C and D implement interface I, and I have an array of each. I'd like to combine these into one I[], but eventually I'd like to cast an element back to its original type. interface I {} class C : I {} class D : I {} void main() { C[] c = [new C, new C]; D[] d = [new D, new D]; auto i = cast(I[]) c ~ cast(I[]) d; assert(cast(C) i[0]); // segfault } casting each array to I[] is fine, but casting an element back to C segfaults (even if it weren't a C, it should just return null, right?)look at what 's auto has created: import std.stdio; interface I {} class C : I {} class D : I {} void main() { C[] c = [new C, new C]; D[] d = [new D, new D]; auto i = cast(I[]) c ~ cast(I[]) d; writeln(typeof(i).stringof); } Your issue comme from auto.
Sep 15 2014
On Tuesday, 16 September 2014 at 06:27:59 UTC, Klaus wrote:On Tuesday, 16 September 2014 at 03:05:57 UTC, Franz wrote:AFACIS there's nothing wrong with his use of casting. It's fine here, because `I` is a base type of `C` and `D`. If it weren't for the arrays, the cast wouldn't even be necessary. I think it's a bug.On Tuesday, 16 September 2014 at 03:03:16 UTC, Franz wrote:writing auto i = cast(I[]) c ~ cast(I[]) d; is just a horrible way of shortcuting the static typing. You write this thinking that i "has to be..." and then you complain latter because the cast does not work. D is a strongly typed lang. in your example you use "auto" because your brain doesnt give you what the type of i has to be, which is an error. D is not a scripting lang. You made a wrong usage of "auto".On Tuesday, 16 September 2014 at 02:21:42 UTC, rcor wrote:i is a I[]I'm back for another round of "is this a bug, or am I doing something stupid?". C and D implement interface I, and I have an array of each. I'd like to combine these into one I[], but eventually I'd like to cast an element back to its original type. interface I {} class C : I {} class D : I {} void main() { C[] c = [new C, new C]; D[] d = [new D, new D]; auto i = cast(I[]) c ~ cast(I[]) d; assert(cast(C) i[0]); // segfault } casting each array to I[] is fine, but casting an element back to C segfaults (even if it weren't a C, it should just return null, right?)look at what 's auto has created: import std.stdio; interface I {} class C : I {} class D : I {} void main() { C[] c = [new C, new C]; D[] d = [new D, new D]; auto i = cast(I[]) c ~ cast(I[]) d; writeln(typeof(i).stringof); } Your issue comme from auto.
Sep 16 2014
On Tuesday, 16 September 2014 at 08:39:43 UTC, Marc Schütz wrote:AFACIS there's nothing wrong with his use of casting. It's fine here, because `I` is a base type of `C` and `D`. If it weren't for the arrays, the cast wouldn't even be necessary. I think it's a bug.Correction: AFAIK casting between interfaces and classes needs to adjust the underlying pointer. Therefore, when casting an array, the compiler would have to do that with the entire array, which cannot be copied without allocating memory (and mustn't be modified in-place for consistency reasons). This means that the cast is instead a pure reinterpret cast (repainting). Whether the compiler should accept that or not is a different question. I guess it should, because if it doesn't, there wouldn't be an easy way to achieve a reinterpret cast (only via an intermediate cast to `void*`, which is clumsy). Anyway, using `std.conv.to` is the way to go here (if you don't require that last bit of performance), because it is safer in general (also checks for overflows and the like, for example).
Sep 16 2014
On Tuesday, 16 September 2014 at 08:49:04 UTC, Marc Schütz wrote:On Tuesday, 16 September 2014 at 08:39:43 UTC, Marc Schütz wrote:Whether the compiler should accept that or not is a different question. I guess it should, because if it doesn't, there wouldn't be an easy way to achieve a reinterpret cast (only via an intermediate cast to `void*`, which is clumsy). Anyway, using `std.conv.to` is the way to go here (if you don't require that last bit of performance), because it is safer in general (also checks for overflows and the like, for example).Thanks, didn't think of trying std.conv.to. Can someone expand a bit on what to! is doing in this situation that cast isn't? I looked up 'reinterpret cast' but didn't see the connection to this.AFAIK casting between interfaces and classes needs to adjust the underlying pointer. Therefore, when casting an array, the compiler would have to do that with the entire array, which cannot be copied without allocating memory (and mustn't be modified in-place for consistency reasons). This means that the cast is instead a pure reinterpret cast (repainting).Is to! creating a new array of pointers while cast isn't? This isn't a performance critical section and it's not a huge array, so I ask mostly out of curiosity.
Sep 16 2014
On Tuesday, 16 September 2014 at 11:26:05 UTC, rcor wrote:On Tuesday, 16 September 2014 at 08:49:04 UTC, Marc Schütz wrote:Reinterpret cast means that the compiler should treat whatever is at the memory location as the given type, and not modify it in any way. `std.conv.to` can do more work, for example it can also parse strings into integers: assert("42".to!int == 42);On Tuesday, 16 September 2014 at 08:39:43 UTC, Marc Schütz wrote:Whether the compiler should accept that or not is a different question. I guess it should, because if it doesn't, there wouldn't be an easy way to achieve a reinterpret cast (only via an intermediate cast to `void*`, which is clumsy). Anyway, using `std.conv.to` is the way to go here (if you don't require that last bit of performance), because it is safer in general (also checks for overflows and the like, for example).Thanks, didn't think of trying std.conv.to. Can someone expand a bit on what to! is doing in this situation that cast isn't? I looked up 'reinterpret cast' but didn't see the connection to this.Yes, it is. (Probably. I don't have the time to test it now, but it's likely if my theory about the pointer adjustment is correct.)AFAIK casting between interfaces and classes needs to adjust the underlying pointer. Therefore, when casting an array, the compiler would have to do that with the entire array, which cannot be copied without allocating memory (and mustn't be modified in-place for consistency reasons). This means that the cast is instead a pure reinterpret cast (repainting).Is to! creating a new array of pointers while cast isn't? This isn't a performance critical section and it's not a huge array, so I ask mostly out of curiosity.
Sep 16 2014
On Tuesday, 16 September 2014 at 14:13:48 UTC, Marc Schütz wrote:On Tuesday, 16 September 2014 at 11:26:05 UTC, rcor wrote:I guess I could have checked that out myself: import std.stdio; import std.conv; interface I {} class C : I {} class D : I {} void main() { C[] c = [new C, new C]; I[] i = cast(I[]) c; I[] i2 = c.to!(I[]); assert(c is cast(C[]) i); // i and c point to same address assert(i !is i2); // to! appears to create a new array }Is to! creating a new array of pointers while cast isn't? This isn't a performance critical section and it's not a huge array, so I ask mostly out of curiosity.Yes, it is. (Probably. I don't have the time to test it now, but it's likely if my theory about the pointer adjustment is correct.)
Sep 16 2014
On Tuesday, 16 September 2014 at 06:27:59 UTC, Klaus wrote:is just a horrible way of shortcuting the static typing. You write this thinking that i "has to be..." and then you complain latter because the cast does not work. D is a strongly typed lang. in your example you use "auto" because your brain doesnt give you what the type of i has to be, which is an error. D is not a scripting lang. You made a wrong usage of "auto".Admittedly this came about as a result of some poor design on my part, but I don't get what you're saying about auto. I thought auto was supposed to relieve the cognitive load of manual type identification. Without it, std.algorithm would be a pain to use. My brain doesn't intuitively tell me that std.algorithm.filter returns a FilterResult, but I can use it effectively with auto.
Sep 16 2014
On 09/15/2014 07:21 PM, rcor wrote:I'm back for another round of "is this a bug, or am I doing something stupid?". C and D implement interface I, and I have an array of each. I'd like to combine these into one I[], but eventually I'd like to cast an element back to its original type. interface I {} class C : I {} class D : I {} void main() { C[] c = [new C, new C]; D[] d = [new D, new D]; auto i = cast(I[]) c ~ cast(I[]) d; assert(cast(C) i[0]); // segfault } casting each array to I[] is fine, but casting an element back to C segfaults (even if it weren't a C, it should just return null, right?)I don't have an answer and I am not even sure whether this is a bug. However, std.conv.to works with the example: import std.conv; interface I {} class C : I {} class D : I {} void main() { C[] c = [new C, new C]; D[] d = [new D, new D]; auto i = c.to!(I[]) ~ d.to!(I[]); // <-- here assert(cast(C)(i[0])); } Ali
Sep 15 2014