www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Inheriting class checks

reply IchorDev <zxinsworld gmail.com> writes:
A common pattern when working with inheriting classes or classes 
that implement an interface is to use the base class or interface 
as a generic type:
```
interface Thing{}
class OtherThing: Thing{}

Thing[] array = [new OtherThing(), …];
```
So how do people usually check if an item in `array` is a 
sub-class of `Thing`, or implements an interface that inherited 
from `Thing`? Is `typeid` the only way to do this?
Aug 09 2023
next sibling parent Arafel <er.krali gmail.com> writes:
On 10/8/23 7:59, IchorDev wrote:
 A common pattern when working with inheriting classes or classes that 
 implement an interface is to use the base class or interface as a 
 generic type:
 ```
 interface Thing{}
 class OtherThing: Thing{}
 
 Thing[] array = [new OtherThing(), …];
 ```
 So how do people usually check if an item in `array` is a sub-class of 
 `Thing`, or implements an interface that inherited from `Thing`? Is 
 `typeid` the only way to do this?
I faced this issue recently. In my case, and I think it's the most common case, I didn't care what exact type it was, I just wanted to make sure it was `OtherThing`. If it wasn't, the exact type didn't really matter. If that's also your case, you can just cast to the type you need, and check for `null`. My case was like this: ```d interface Thing{ void foo(Thing[] array); } class OtherThing: Thing{ override void foo(Thing[] array) { foreach (thing; array) { auto otherThing = cast (OtherThing) thing; assert(otherThing, "Wrong type in `array`: " ~ typeid(thing).toString); // Do something here } } } ```
Aug 10 2023
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 8/10/23 1:59 AM, IchorDev wrote:
 A common pattern when working with inheriting classes or classes that 
 implement an interface is to use the base class or interface as a 
 generic type:
 ```
 interface Thing{}
 class OtherThing: Thing{}
 
 Thing[] array = [new OtherThing(), …];
 ```
 So how do people usually check if an item in `array` is a sub-class of 
 `Thing`, or implements an interface that inherited from `Thing`? Is 
 `typeid` the only way to do this?
The *correct* way is to use a cast. Though, that can be overridden. A very nice pattern in D is: ```d if(auto x = cast(DerivedTypeOrInterface)y) { // use x } ``` This also can be dangerous if e.g. `y` in the future becomes `const`. This is one place where pattern matching would be very useful. In fact, we already do it for try/catch, I don't see why we can't do it in general. -Steve
Aug 10 2023
next sibling parent Nick Treleaven <nick geany.org> writes:
On Thursday, 10 August 2023 at 15:25:41 UTC, Steven Schveighoffer 
wrote:
 The *correct* way is to use a cast. Though, that can be 
 overridden.

 A very nice pattern in D is:

 ```d
 if(auto x = cast(DerivedTypeOrInterface)y) {
    // use x
 }
 ```

 This also can be dangerous if e.g. `y` in the future becomes 
 `const`.
To avoid both the opCast and the casting away const problem, perhaps std.conv should have: ```d D derived(D, B : Object)(B base) if (is(D : B) && !__traits(compiles, base.opCast!D)) { return cast(D)base; } alias E = Exception; void main() { Object o = new E("hi"); E c = o.derived!E; assert(c.msg == "hi"); } ``` There's probably some way to statically enforce that `B` has `extern(D)` linkage, `derived` could enforce that too. (`extern(C++)` classes don't have RTTI).
Aug 11 2023
prev sibling next sibling parent reply IchorDev <zxinsworld gmail.com> writes:
On Thursday, 10 August 2023 at 15:25:41 UTC, Steven Schveighoffer 
wrote:
 This also can be dangerous if e.g. `y` in the future becomes 
 `const`.
But what if `y` is `const`, or even `immutable`? How is it dangerous?
Aug 12 2023
parent Nick Treleaven <nick geany.org> writes:
On Saturday, 12 August 2023 at 09:32:14 UTC, IchorDev wrote:
 On Thursday, 10 August 2023 at 15:25:41 UTC, Steven 
 Schveighoffer wrote:
 This also can be dangerous if e.g. `y` in the future becomes 
 `const`.
But what if `y` is `const`, or even `immutable`? How is it dangerous?
Because the cast removes the type qualifier, so could allow mutation of immutable data. In safe code I expect that situation would error.
Aug 12 2023
prev sibling parent reply Dom DiSc <dominikus scherkl.de> writes:
On Thursday, 10 August 2023 at 15:25:41 UTC, Steven Schveighoffer 
wrote:
 A very nice pattern in D is:

 ```d
 if(auto x = cast(DerivedTypeOrInterface)y) {
    // use x
 }
 ```

 This also can be dangerous if e.g. `y` in the future becomes 
 `const`.
I hate this. Why don't we have an "unqual cast" (a cast that changes the type but leave all qualifiers unchanged)? That should not be complicated to implement, but would be useful very often.
Aug 12 2023
parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
This should work:

```d
import std.traits : CopyTypeQualifiers;

if(auto x = cast(CopyTypeQualifiers!(typeof(y), DerivedTypeOrInterface))y) {
    // use x
}
```
Aug 12 2023