How to check if a type is a subtype of another in dart - flutter

I've recently found myself in a situation where I wanted to check if a Type is a subtype of another Type this is what I've tried
abstract class Record{}
class TimeRecord extends Record{}
void test(){
print(TimeRecord is Record); // return false but why ??
}

The only time it makes sense to check if one type is a subtype of another type is when at least one of the types is a type variable. (Otherwise, you can just look at the source and write a constant true or false into the code).
There is a way to check whether one type is a subtype of another, and it does use the is operator, but you need to have an instance as the first operand and a type as the second. You can't just create an instance of an unknown type, so we instead rely in Dart's covariant generics:
bool isSubtype<S, T>() => <S>[] is List<T>;
(You can use any generic class, or even create your own, instead of using List. All it needs is a way to create the object.)
Then you can write:
print(isSubtype<TimeRecord, Record>()); // true!

The is keyword is used to check if an object instance is an object of type T, and not if a type is another type:
abstract class Record{}
class TimeRecord extends Record{}
void test(){
print(TimeRecord() is Record); // returns true!
}

Just to add up to #lrn answer.
You could also do something like:
extension NullableObjectsExtensions<T> on T {
bool isSubtypeOf<S>() => <T>[] is List<S>;
bool isSupertypeOf<S>() => <S>[] is List<T>;
}
So this way you can test any variable anywhere.

Related

Dart - Limit generic constrained type to sub type

i am currently working with Flutter/Dart. I want to implement a generic helper class, which puts a received input value into a generic wrapper, depending on the type.
Here the example code:
class ClassA {}
class ClassB<T> {
ClassB(this.t);
final T t;
}
class ClassC<T extends ClassA? {
ClassC(this.t);
final T t;
}
class ClassD<T> {
ClassD(this.t);
final T t;
Object getWrapper(){
final t = this.t;
return T == ClassA?
? ClassC<T>(t) //<--fails
: ClassB<T>(t);
}
}
Produces:
'T' doesn't conform to the bound 'ClassA?' of the type parameter 'T'.
ClassD is the helper which produces the wrappers. For the wrapper ClassB there is no isdue, but i could not get it to work for the wrapper ClassC. As it constrains its generic type it conflicts with the generic type of the wrapper itself, although i also included a type check there to limit the type to the constrained one.
I am wondering why this won't work and how it could be adjusted to make it work.
I tried to add a type check and adjusted it in various ways like
T == ClassA
or
T is ClassA
also including the local variable t
T == ClassA && t is ClassA

How to cast an object with a generic type

I have this small code snippet:
class A<T> {
A(this.a);
final T a;
}
void main() {
final a = A(true);
print(a);
print(a as A<bool>);
final b = A<Object>(true);
print(b);
print(b as A<bool>);
}
I'm receiving the object b from a library/API which is a A<Object> (and I don't have control over it), but I know it is actually a A<bool> in my specific case. I'm trying to cast it to A<bool> (as in my code snippet with b). But I get an error saying that A<Object> is not a subtype of A<bool>.
Here are the logs from the code snippet pasted above:
Instance of 'A<bool>'
Instance of 'A<bool>'
Instance of 'A<Object>'
Uncaught Error: TypeError: Instance of 'A<Object>': type 'A<Object>' is not a subtype of type 'A<bool>'
How can I cast b (a A<Object>) into a A<bool>?
How can I cast b (a A<Object>) into a A<bool>?
You can't. They're not the same type.
b was constructed as an A<Object>, so its runtime type is A<Object>, regardless of whether b.a happens to be referring to a bool. A cast with as changes the static (known to the compiler) type of an object, but you cannot change an object's runtime type. If you want an object with a different runtime type, you must construct a separate object.
Let's consider a slightly different example:
class C<T> {
T value;
C(this.value);
}
C<T> is the same thing as A<T> except that its member is not final. If casting an object with a runtime type of C<Object> to C<bool> were allowed, then we could have the following:
final c = C<Object>(true);
final casted = c as C<bool>; // Should this be allowed?
c.value = 'Hello world!'; // Legal since `c.value` is of type `Object`.
bool someBool = casted.value; // ???
Arguably the case for casting A is different; A's member is final and therefore wouldn't lead to the above scenario. However, I'd expect that that kind of exception would add a lot of complexity and possibly could make things even more confusing.
Also see: https://stackoverflow.com/a/67223011/
The following code can cast it. dont know if it works in your case.
var c = A<bool>(b.a as bool);
/// OR
extension Cast on A<Object> {
A<bool> cast() => A<bool>(a as bool);
}

Enumeration subtype element as parameter in Scala

I have a generic class for which the type must be a subtype of Enumeration
class MyClass[A<: Enumeration](val parameter1 : Int,
val parameter2: A) {
}
Inside this class, there is a method that needs to take an element from the enum A as parameter. I cannot find the proper way to write the signature of the method.
def myMethod(element: A.Values): Resource2[A] = {
this
}
Intellisense says
Cannot resolve symbol A
How can I write the method so it takes an element of the enum A ?
The type is Value (not Values) and, because A is a type and not an instance (i.e. not a value), the syntax for referencing a type within a type is element: A#Value.

implicitely set an associated type

I'm trying to figure out how to implicitely set a Generic (type of a argument) in a class without changing the type of the whole class to something like SomeTestClass< SomeType>, where the owner of an object has to know the type of the generic.
Example
This example DOESNT work! This is how I would like it to work
protocol SomeTestProtocol {
associatedtype T
init(arg: T)
}
Don't want to use SomeTestClass< T>
because the class, which holds this class
wont know the type of the generics used
class SomeTestClass: SomeTestProtocol {
required init(arg: T) {
}
// Use T outside the init-scope
}
Note: The Protocol is just a try for a work-around! It isn't necessary for the final solution
So the main question is: How can I use T outside the init-scope in the class below without using a class-generic, which must be known when owning an object
class SomeTestClass2/*< T>*/ {
init(arg: T) {
}
// Use T outside the init-scope
}
Thanks for your help!
Important note, the T from associatedtype T and the T from init<T> can be different types. They are both defining a generic type with different scopes an could be different. If you want them to be the same, the init should be
init(arg: T)
If SomeTestClass is always going to use the same type, you can add
typealias T = Int // or something
or implement the init as
required init(arg: Int)
It works if you get rid of the associatedtype T from the protocol. Though this removes SomeTestClass.T form existence.
If you declare an associated type in a protocol, that type will become generic over different implementations of the protocol, but each conforming class will need to assign a concrete type to that associate type as a typealias (which can be done implicitly by declaring all variables/functions using the associated type with the same concrete type), so your conforming types won't be generic.
If you want to have generic methods in your conforming classes, you'll need to make the classes themselves generic.
If you only want access to T outside of init, then you just store T in a property:
class S {
let theType: Any.Type
init<T>(arg: T) {
theType = T.self
}
}
I suspect you actually want something different than what you've said you want. I suspect you want to store arg. But if so, what do you plan to do with arg if you have no idea what its type is? What methods can you call? What function could it be the return value of? Without resorting to as?, there's nothing you can do with T (and reliance on as? generally means you've misunderstood your types).
So you need to start with how you want T and SomeTestClass to be used. Without that, it's impossible to discuss how T should be stored (the storage is irrelevant if you never use it).

Set the "double" restriction for a generic parameter

I have 3 classes:
abstract class Abs1 { ... }
abstract class Abs2 { ... }
class MyClass[T <: /*Abs1 or Abs2*/] { ... }
Is there any way specify that T must be a child of Abs1 or Abs2?
In short: no.
What would that mean for an object of type T? What method would you be able to call, since you do not know whether it has any methods exposed in Abs1 (since it might be a type derived from Abs2) or any methods exposed in Abs2 (since it might be a type derived from Abs1). You could only used methods defined for Any, or any other common parent of Abs1 and Abs2 if they have some.
In this case, you might as well accept this super type directly, and manipulate Any (or a common parent type of Abs1 and Abs2) objects in your methods rather than objects of type T. Or you could not put any constraint on T: that would give you a generic class that you can instantiate with any specific type, but you would not know anything about this type either except that it derives from Any.