Jump to page: 1 2
Thread overview
Segfault when casting array of Interface types
Sep 16, 2014
rcor
Sep 16, 2014
Franz
Sep 16, 2014
Franz
Sep 16, 2014
rcor
Sep 16, 2014
rcor
Sep 16, 2014
Klaus
Sep 16, 2014
Marc Schütz
Sep 16, 2014
Marc Schütz
Sep 16, 2014
rcor
Sep 16, 2014
Marc Schütz
Sep 16, 2014
rcor
Sep 16, 2014
rcor
Sep 16, 2014
Ali Çehreli
September 16, 2014
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?)
September 16, 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.

September 16, 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'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.

i is a I[]


September 16, 2014
On Tuesday, 16 September 2014 at 03:05:57 UTC, Franz wrote:
>> Your issue comme from auto.
>
> i is a I[]

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.
September 16, 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[].
September 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

September 16, 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:
>> 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.
>
> i is a I[]

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".

September 16, 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:
>> 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'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.
>>
>> i is a I[]
>
> 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".

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.
September 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).
September 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.
« First   ‹ Prev
1 2