Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does FutureOr<T> have a reified type of Future<T> / <T>?

Tags:

dart

I have a class in AngularDart as followings:

abstract class Validator {
  Map validate(AbstractControl c);
}

Looking closely, this used to be (before we added strong-mode support):

abstract class Validator {
  validate(AbstractControl c);
}

The issue that it technically supports returning a Future or Map.

I'd like to refactor this and properly type it using FutureOr:

abstract class Validator {
  FutureOr<T> validate(AbstractControl c);
}

Will I be able to use an is check at runtime? (In DDC and dart2js)

void runValidator(Validator v) {
  var result = v.validate(...);
  if (result is Future) {
    // async...
  } else {
    // sync...
  }
}

Am I thinking about this correctly?

EDIT: As mentioned below, I mean

if (result is Future<T>) {

} else if (result is T) {

}

One more question, would validate match these two typedefs:

Future<Map> AsyncValidate(AbstractControl c);

Map SyncValidate(AbstractControl c);
like image 765
matanlurey Avatar asked Oct 18 '22 17:10

matanlurey


1 Answers

Yes, you can do result is Future<Map>. The actual value returned by the validate method is either a Future or it's not. The static type of the function doesn't affect that, and since FutureOr<Map> isn't an actual class, you can't have an object that is "a FutureOr". It's either a real Future<Map> or it's a Map.

For the second question, that depends on what yo mean by "match". You can override the method with a method that returns either Map or FutureMap:

abstract class Validator {
  FutureOr<Map> validate(abstractControl c);
}
class AsyncValidator extends Validator { 
  Future<Map> validate(AbstractControl c) {...}   
}
class SyncValidator extends Validator { 
  Map validate(AbstractControl c) {...} 
}

That is, you can use one of the function types you mention as a Validator.validate, but not in the other direction.

typedef FutureOr<Map> Validate(AbstractControl c);
typedef Future<Map> AsyncValidate(AbstractControl c);
typedef Map SyncValidate(AbstractControl c);
Validator v = ...;
Validate f0 = v.validate;  // Safe.
AsyncValidate f1 = v.validate; // BAD assignment.
SyncValidate f2 = v.validate; // BAD assignment.

Map syncValidate(AbstractControl c) { ... }
Future<Map> asyncValidate(AbstractControl c) { ... }
v = syncValidate;  // Good assignment.
v = asyncValidate;  // Good assignment.    

In practice, the concrete validate method of the validator v will probably be assignable to one of f1 or f2, but its static type doesn't say which one, so both are considered bad assignments.

You should only very rarely have a non-abstract method that is declared as returning FutureOr. In most cases, it's better to just always return a Future or a non-Future, and declare the method as such. Then you can always use the function as returning FutureOr if you need to, but use the more precise type in cases where you need it.

like image 84
lrn Avatar answered Oct 21 '22 02:10

lrn