Differentiate classes and subclasses

Hi!

I’m trying to programmatically override default classes with their extended version in an array but I fall short to finding a direct implementation.

class A {}
class B {}
class C {}
class D {}

class Ax extends A{}
class Cx extends C{}


void main() {
  
  final base = [A(),B(),C(),D()];
  final ex = [Ax(), Cx()];
  
  // expected result
  final rs = [Ax(), B(), Cx(), D()];
  
}

What could be the simplest way to compare instances and determine if they are subclass of a parent instance?

I can solve it by adding others variables to the code but I surely miss some evident solution!

Thanks for sharing your approach.

You want to directly compare instances without using the types of the instances and you want to know which is a subtype of another one?

Yes if an entry is an override then replace the original instance.

Available tools are ‘is’ and ‘runtime’ but is can not be used in a dynamic way.

I’m not aware of any way to determine if Ax extends A at runtime.

An explicit instance is A and instance.runtime != A would do but there’s too many classes in my code and it’s not really effective to write code like that.

The case is very common but it’s the first time I’ve to deal with that pattern in Dart and i’m looking for a scalable solution.

1 Like

I fear that you won’t find a general solution for this without any code generation that for instance creates type matching switch statements.

So you probably will need to add some properties that hold the needed information.
maybe @munificent or @CraigLabenz has another idea.

That’s what I feared… I won’t go code gen as VS code break when in any real codebase and it’s too heavy to solve such a basic case. I’ll go with the verbose solution, surely an Enum field.

Is there a ticket on the subject and what in the dart protocol would block an helper method.

Thanks Thomas.

I think it’s the problem that Dart objects lack needed information about type hierarchies at runtime. I was bitten by that several times in the past even if you want to compare static types.

Instead of an enum you could also think of defining a set of interfaces so you could at least to some is comparisons.

I published here a simpler version of a hierarchy that is a assemblage of sealed and others type oriented identifiers.
It break the analyzer enough that I don’t want to tinker with it anymore :smiley:

Is the dart protocol still alive and discussed about evolving to more advanced OO/FP helpers or Meta is taking all the bandwidth?

I’m hitting a lot of walls lately.

I guess that we will get some options with the upcoming meta programming.
I don’t expect that we will get more runtime type information soon

The runtime does keep around enough information to be able to answer queries like “Is this object and instance of a class that is a subtype of this other object’s class?” But there isn’t a core library that actually exposes that information, except for “dart:mirrors”. Using that library, you could do this. You’d reflect each object, get their class, and then walk the supertypes to look for matches.

However, using mirrors is discouraged, only works on the VM, can have bad impacts on code size, and is probably quite slow.

I wish there was a simpler, more reliable API to let you ask these kinds of questions but currently Dart doesn’t expose any.

6 Likes

@munificent but it would be possible in AOT compilation if we had another core library to give the access?
What’s the reason that part is not open?

My program is large enough that I rely completely on Dart to hold the structure and can’t bother with coming with my own variables to manage all this (array, enum, flag, …).
Class hierarchy got all the infos already.

It’s a reassuring info to know that the Vm knows all this and we just need to prioritize features in the future.

Coming years surely but is there a ticket I can upvote?

I wish to see Dart beyond just mobile dev so anything related to complexity management and modelisation hold by the language has much much much value to me.

2 Likes

If I understand what you wanna do, you can use these helper functions:

class A {}
class B {}

class Ax extends A{}

Type typeOf<T>(T _) => T;

bool typeIsSubtypeOf<T1, T2>(T1 _, T2 __) => <T1>[] is List<T2>;

void main() {
  final a = A();
  final b = B();
  final ax = Ax();

  // equality
  print(typeOf(ax) == typeOf(ax)); // true
  print(typeOf(ax) == typeOf(a)); // false
  print(typeOf(ax) == typeOf(b)); // false
  
  
  // subtype
  print(typeIsSubtypeOf(a, ax)); // false
  print(typeIsSubtypeOf(ax, a)); // true
  print(typeIsSubtypeOf(ax, b)); // false
}
2 Likes

Hey thanks joining the discussion.

This is the part I can not afford
bool typeIsSubtypeOf<T1, T2>(T1 _, T2 __) => <T1>[] is List<T2>;

As it means handling all the hierarchy of dozens of classes by explicit line of code instead of relying of declaration. And I use list for demonstration but the real program compose structure. It would also be kinda problematic with Axa that extend Ax… welcome T3 :slight_smile:

I went with an Enum that is more maintainable but prone, like the previous line to declaration omission. All subclass then inherit the value and can replace detected parent in hierarchy.

Without a whole package the solution would be kotlin like ax.isSubclassOf(a) for instances ax.isSubclassOf<A>() for type.

@BlueAquilae Wait, have you tried the function he proposed?
The part with te list is just a trick to allow the ‘is’ comparison.
For my understanding it could work because Dart will automatically assign the not provided generics the type of the parameter that you pass.
You use the same functions for all your types.

Exactly. Plus you can probably even make it into an extension so you can call obj1.isSubclassOf(obj2) or ax.isSublassOfType<A>() etc.

Thank for you attention to details!
If I went through that what a loss it would be.
I’m try to port in my test case right now?

1 Like

Nearly there, I’m failing my UTs as it seems there’s a corner case I need to identity.
Something related to mixin or class extension and now everything is typeIsSubtypeOf but for simple cases it may well work!

Gonna try to head my around this magic trick

Really curious if this works.
I fear you might get to a limit if you pass an object through a more generic function parameter, these functions won’t be able to deliver any information

2 Likes

At least it was really fun to try!
This forum found its mission.

3 Likes

This approach works well if you have the type definitions propagated via generic parameters.