You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Reflectable (like any other approach to Dart reflection based on code generation) cannot obtain the actual type arguments of a given instance:
classA {}
classBimplementsA {}
main() {
Iterable<dynamic> x =<B>[];
if (x isIterable<A>) { /* We can confirm a given type argument */ }
// .. but we cannot obtain the actual type argument, and we may not// have a type like `B` in scope, and the set of actual type arguments// in the execution of a given program is undecidable, so we can't even// hope to try all possibilities and thereby find the most specific type `T`// such that `x is Iterable<T>`, which will be the actual type argument// of the class of `x` at `Iterable`.
}
There is no general approach that reflectable could apply to provide access to the actual type argument A (via a mirror or as a Type) because reflectable mirrors run regular (though generated) code. We can only confirm any upper bound that we may already know to ask for.
As a consequence, the following will execute both print statements:
import'package:reflectable/reflectable.dart';
import'main.reflectable.dart';
classReflectorextendsReflectable {
constReflector() :super(invokingCapability, typingCapability,
reflectedTypeCapability);
}
constReflector reflector =constReflector();
@reflectorclassSecurityService {}
@reflectorclassSpecialSecurityServiceimplementsSecurityService {}
@reflectorclassMyGenericService<XextendsSecurityService> {}
main() {
initializeReflectable();
MyGenericService service =MyGenericService<SpecialSecurityService>();
InstanceMirror instanceMirror = reflector.reflect(service);
ClassMirror classMirror = instanceMirror.type;
try {
classMirror.typeArguments;
} onUnimplementedErrorcatch (_) {
print("Cannot obtain actual type arguments as mirrors.");
}
try {
classMirror.reflectedTypeArguments;
} onUnimplementedErrorcatch (_) {
print("Cannot obtain actual type arguments as `Type` values.");
}
}
Until now, this feature (the ability to extract actual type arguments from a given instance) has been marked as unimplemented, stating that we cannot get this feature until some additional primitives are made available. That is still true, in the general case.
However, we could adopt an approach where the developer of a given class could opt in to provide support for extracting actual type arguments, because that's easy to do as soon as we allow the implementation to exist in the target class:
classSecurityService {}
classSpecialSecurityServiceimplementsSecurityService {
voidspecial() =>print('Doing very special stuff!');
}
classClient<XextendsSecurityService> {
X service;
Client(this.service);
YopenClient<Y>(YFunction<ZextendsSecurityService>(Client<Z>) f) {
returnf<X>(this);
}
}
main() {
finalClient<SpecialSecurityService> exactlyTypedClient =Client(SpecialSecurityService());
// Forget the actual type argument.finalClient<SecurityService> client = exactlyTypedClient;
// Create a function which can be used to open a client.voidshowActualTypeArgument<XextendsSecurityService>(Client<X> self)
=>print(X);
// Prints 'SpecialSecurityService': Accesses the actual value of `X`.
client.openClient(showActualTypeArgument);
// We may even use `X` as a type.
client.openClient(<XextendsSecurityService>(self) {
X service = self.service;
self.service = service;
// We can't statically establish that `X <: SpecialSecurityService`,// but we can of course still perform a direct type test.if (service isSpecialSecurityService) {
// Promotion gives `service` an intersection type such that we can// both use the features of `SpecialSecurityService` and preserve the// relationship to `X`.
service.special();
X xService = service; // Accepted also with `--no-implicit-casts`.
}
});
}
We would then check for the existence of a method named openC during processing of any given class C which has a suitable signature (that is, it must declare the same type argument list as C, and it must accept an argument which can be this, with the most specific type), and the code generated by reflectable would then be able to use those open... methods in generated code.
It is also possible that this won't help enough to be worthwhile, but this issue serves to discuss that and reach a decision.
Finally, you could of course say that reflectable can just edit the code of existing classes (that's also a kind of code generation, you are just generating a modified variant of "the whole universe" of libraries that a given program uses), but we opted out of doing any such thing a long time ago:
First, it will not work for entities that have no code (and nobody guarantees that dynamic or int exist as declarations in Dart, and even if they do, we can't expect to be able to "edit the code of int" and still make compiled programs work, because the runtimes can make special assumptions about such built-in classes).
Second, the build package obtains a number of good properties from the design decision of only generating fresh code, never editing existing code.
The text was updated successfully, but these errors were encountered:
Unfortunately, we still don't have the primitives that we'd need, so there is no way right now to implement general support for obtaining access to the actual type arguments at a specific type for a given instance.
It is possible that we will get such primitives as part of an likely upcoming enhancement known as extension methods (dart-lang/language#41, dart-lang/language#177), but even that will take some time.
Reflectable (like any other approach to Dart reflection based on code generation) cannot obtain the actual type arguments of a given instance:
There is no general approach that reflectable could apply to provide access to the actual type argument
A
(via a mirror or as aType
) because reflectable mirrors run regular (though generated) code. We can only confirm any upper bound that we may already know to ask for.As a consequence, the following will execute both print statements:
Until now, this feature (the ability to extract actual type arguments from a given instance) has been marked as unimplemented, stating that we cannot get this feature until some additional primitives are made available. That is still true, in the general case.
However, we could adopt an approach where the developer of a given class could opt in to provide support for extracting actual type arguments, because that's easy to do as soon as we allow the implementation to exist in the target class:
We would then check for the existence of a method named
openC
during processing of any given classC
which has a suitable signature (that is, it must declare the same type argument list asC
, and it must accept an argument which can bethis
, with the most specific type), and the code generated by reflectable would then be able to use thoseopen...
methods in generated code.It is also possible that this won't help enough to be worthwhile, but this issue serves to discuss that and reach a decision.
Finally, you could of course say that reflectable can just edit the code of existing classes (that's also a kind of code generation, you are just generating a modified variant of "the whole universe" of libraries that a given program uses), but we opted out of doing any such thing a long time ago:
dynamic
orint
exist as declarations in Dart, and even if they do, we can't expect to be able to "edit the code ofint
" and still make compiled programs work, because the runtimes can make special assumptions about such built-in classes).build
package obtains a number of good properties from the design decision of only generating fresh code, never editing existing code.The text was updated successfully, but these errors were encountered: