www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Why does this code only work with `std.conv.to` whilst not with

reply thebluepandabear <therealbluepandabear protonmail.com> writes:
I've been writing some code and I have been experimenting with 
casting. I've found that sometimes only `std.conv.to!` does the 
job over casting, and I am unsure why this is the case as I 
assumed that they are both the same.

I have the following interface:

```D
interface ICustomDrawable {
     void render(sfRenderWindow* renderWindow);
}
```

And the following class that implements that interface:

```D
class Button : ICustomDrawable {
     ...
     override void render(sfRenderWindow* renderWindow) {
         ...
     }
}
```

And this class which uses `ICustomDrawable`:

```D
class StackLayout : ICustomDrawable {
    ...
     void addChild(T)(T child) {
         static assert(is(T : ICustomDrawable), "Invalid type T 
for child");
         ...
     }
     ...
     ICustomDrawable[] _children;
}
```

For some reason, when I want to cast the `children` (property), 
only the second example works:

1.

```D
foreach (Button button; cast(Button[])(_boardSizeRow.children)) {
     button.update(event, _renderWindow);
}
```

2.

```D
foreach (Button button; to!(Button[])(_boardSizeRow.children)) {
     button.update(event, _renderWindow);
}
```

When I run the first code example I get a black screen, whilst 
with the second I do not. I find this very strange as when I 
write to the console the 'type', it is the same for both 
scenarios.

Help would be appreciated as to why this is happening so I can 
better understand how D works.
Jan 08 2023
next sibling parent ag0aep6g <anonymous example.com> writes:
On 08.01.23 12:29, thebluepandabear wrote:
 ```D
 interface ICustomDrawable {
      void render(sfRenderWindow* renderWindow);
 }
[...]> class Button : ICustomDrawable { [...]
 }
[...]
 class StackLayout : ICustomDrawable {
[...]
      ICustomDrawable[] _children;
 }
 ```
 
 For some reason, when I want to cast the `children` (property), only the 
 second example works:
 
 1.
 
 ```D
 foreach (Button button; cast(Button[])(_boardSizeRow.children)) {
      button.update(event, _renderWindow);
 }
 ```
 
 2.
 
 ```D
 foreach (Button button; to!(Button[])(_boardSizeRow.children)) {
      button.update(event, _renderWindow);
 }
 ```
Two things you need to know: 1. While an interface reference implicitly converts to a compatible class reference, the resulting pointer is slightly different. ---- interface I {} class C : I {} void main() { C c = new C; I i = c; import std.stdio; writeln(cast(void*) c); /* e.g. 7F3C140A7000 */ writeln(cast(void*) i); /* e.g. 7F3C140A7010 */ } ---- 2. Casting from one array type to another is done "as a type paint"[1]. The elements of the array are reinterpreted, not converted. But reinterpreting interface references as class references won't work, because the pointers will be wrong. You need to convert each element of the array (which is what `to` does). [1] https://dlang.org/spec/expression.html#cast_array
Jan 08 2023
prev sibling parent reply matheus <matheus gmail.com> writes:
On Sunday, 8 January 2023 at 11:29:10 UTC, thebluepandabear wrote:
 ...
There is an explanation here: https://forum.dlang.org/post/tqukutfzeaxedunuvkum forum.dlang.org But in any case I'd like to point it out that I think you could do that foreach without casting or std.conv by just omitting the type of the variable you're iterating: import std.stdio, std.conv; interface IDog { void bark(); } class Dog: IDog{ string s; this(string _s){s = _s;} void bark(){writeln(s);} } class List{ IDog[] dogs; void add(T)(T d){ dogs ~= d; } } void main(){ auto d1 = new Dog("meaw!"); auto d2 = new Dog("wof!"); auto l = new List(); l.add(d1); l.add(d2); foreach(d; l.dogs){ // No type informed for "d" d.bark(); } } Prints: meaw! wof! Matheus.
Jan 08 2023
parent reply thebluepandabear <therealbluepandabear protonmail.com> writes:
On Sunday, 8 January 2023 at 12:35:38 UTC, matheus wrote:
 On Sunday, 8 January 2023 at 11:29:10 UTC, thebluepandabear 
 wrote:
 ...
There is an explanation here: https://forum.dlang.org/post/tqukutfzeaxedunuvkum forum.dlang.org But in any case I'd like to point it out that I think you could do that foreach without casting or std.conv by just omitting the type of the variable you're iterating: import std.stdio, std.conv; interface IDog { void bark(); } class Dog: IDog{ string s; this(string _s){s = _s;} void bark(){writeln(s);} } class List{ IDog[] dogs; void add(T)(T d){ dogs ~= d; } } void main(){ auto d1 = new Dog("meaw!"); auto d2 = new Dog("wof!"); auto l = new List(); l.add(d1); l.add(d2); foreach(d; l.dogs){ // No type informed for "d" d.bark(); } } Prints: meaw! wof! Matheus.
The `foreach` worked for that case since `bark` is a method of `IDog`. `update` is not so a conversion to `Button[]` is needed. I will look at your resource, thanks.
Jan 08 2023
parent matheus <matheus gmail.com> writes:
On Sunday, 8 January 2023 at 12:39:37 UTC, thebluepandabear wrote:
 ...
 The `foreach` worked for that case since `bark` is a method of 
 `IDog`. `update` is not so a conversion to `Button[]` is needed.
In that case, you could do a casting like this: import std.stdio, std.conv; interface IDog { void bark(); } class Dog: IDog{ string s; this(string _s){s = _s;} void bark(){writeln(s);} void update(string _s){ s ~= " - " ~ _s; } } class List{ IDog[] dogs; void add(T)(T d){ dogs ~= d; } } void main(){ auto d1 = new Dog("meaw!"); auto d2 = new Dog("wof!"); auto l = new List(); l.add(d1); l.add(d2); foreach(i,d; l.dogs){ // I'm using 'i' just to show each update. (cast(Dog)d).update(to!string(i)); d.bark(); } } Prints: meaw! - 0 wof! - 1 Matheus.
Jan 08 2023