reflectable 2.2.4

  • Readme
  • Changelog
  • Example
  • Installing
  • 94

Reflectable #

A listing of known limitations is given at the end of this page.

Introduction #

This package provides support for reflection which may be tailored to cover certain reflective features and omit others, thus reducing the resource requirements at run time.

The core idea is that the desired level of support for reflection is specified explicitly and statically, and any usage of reflection at run time must stay within the boundaries thus specified; otherwise a NoSuchCapabilityError is thrown. In return for statically confining the required reflection support, programs can be smaller. Other than that, using this package and using dart:mirrors is very similar.

The core concept in the reflection support specification is that of a reflectable capability. For a more detailed discussion about capabilities, please consult the reflectable capability design document. On this page we just use a couple of simple special cases.

This package uses code generation to provide support for reflection at the level which is specified using capabilities. The build package is used to manage the code generation, and a major part of this package is concerned with generating that code. It is specified which programs to transform, and certain elements in the program itself are used to decide how to transform it. As a result, the transformed program will contain generated code providing the requested level of support for reflection.

The use of dynamic reflection is supported if and only if the usage is covered by the set of capabilities specified.

In general, reflection is provided via a subclass of the class Reflectable (we use the term reflector to designate an instance of such a subclass).

class Reflector extends Reflectable {
  const Reflector() : super(capability1, capability2, ...);

Reflection is disabled by default, and it is enabled by specifying reflectable capabilities. With Reflector we have specified that capability1, capability2, and so on must be supported. The main case for using this is annotating a given class A with a reflector. This implies that the specified level of reflection support for that reflector should be provided for the class A and its instances.

class A {

Only classes covered by a reflector R and their instances can be accessed reflectively using R, and that access is constrained by the capabilities passed as the superinitializer in the class of R. The basic case is when R is used as an annotation of a given class (as is the case with A above), but a class C can also be covered by a reflector R because a supertype A of C is annotated by a reflector which specifies that subtypes of A are covered. There are several other indirect mechanisms in addition to subtype based coverage, as described in the capability design document.

As a result, the available universe of reflection related operations is so well-known at compile time that it is possible to specialize the support for reflection to a purely static form that satisfies the requirements of the given annotations and capabilities.

Usage #

Here is a simple usage example. Assume that we have the following code in the file web/main.dart:

import 'package:reflectable/reflectable.dart';
import 'main.reflectable.dart'; // Import generated code.

// Annotate with this class to enable reflection.
class Reflector extends Reflectable {
  const Reflector()
      : super(invokingCapability); // Request the capability to invoke methods.

const reflector = const Reflector();

@reflector // This annotation enables reflection on A.
class A {
  final int a;
  greater(int x) => x > a;
  lessEqual(int x) => x <= a;

main() {
  initializeReflectable(); // Set up reflection support.
  A x = new A(10);
  // Reflect upon [x] using the const instance of the reflector:
  InstanceMirror instanceMirror = reflector.reflect(x);
  int weekday = new;
  // On Fridays we test if 3 is greater than 10, on other days if it is less
  // than or equal.
  String methodName = weekday == DateTime.FRIDAY ? "greater" : "lessEqual";
  // Reflectable invocation:
  print(instanceMirror.invoke(methodName, [3]));

It is necessary to import the generated code, which is stored in a library whose file name is obtained by taking the file name of the main library of the program and adding .reflectable. In the example, this amounts to import 'main.reflectable.dart'.

Note that it is not recommended to publish generated code, i.e., published packages on should not include files whose name is of the form *.reflectable.dart. The reason for this is that the generated code may change because some direct or indirect dependency changes (say, your package indirectly imports package path and then path changes), and this could make some generated code invalid.

It is also necessary to initialize the reflection support by calling initializeReflectable(), as shown at the beginning of main in the example.

You also need to add the following dependency to your 'pubspec.yaml':

  reflectable: any

You may also wish to specify constraints on the version, depending on the approach to version management that your software otherwise employs.

The root of your library may need to contain a file build.yaml which will specify how to run the code generation step. For an example of how to write this file, please consult test_reflectable/build.yaml and the general documentation about package build.

In order to generate code you will need to run the following command from the root directory of your package:

> pub run build_runner build DIR

where DIR should be replaced by a relative path that specifies the directory where the entry point(s) are located, that is, the main file(s) for the program(s) that you wish to generate code for. In the example where we have an entry point at web/myProgram.dart the command would be as follows:

> pub run build_runner build web

You may appreciate the following shortcut command which will work when you wish to generate code for entry points in the test subdirectory and also run the tests (given that the tests are written using package test):

> pub run build_runner test

This approach (using pub run build_runner ...) includes support for incremental code generation, that is, it offers shorter execution times for the code generation step because strives to only generate code that relies on something that changed. This is the recommended approach.

However, if you have a complex setup then you may wish to study the packages build, build_runner, etc. in order to learn more about how to control the build process in more detail.

To give a hint about a more low-level approach, you may choose to write a tiny Dart program which imports the actual builder, and run the build process from there, rather than using pub run build_runner .... This will give you more control, but also more ways to shoot yourself in the foot.

Here's an example which shows how to get started. The code of such a builder program can be as concise as the following:

import 'package:reflectable/reflectable_builder.dart' as builder;

main(List<String> arguments) async {
  await builder.reflectableBuild(arguments);

You may now run the code generation step with the root of your package as the current directory:

> dart tool/builder.dart web/myProgram.dart

where web/myProgram.dart should be replaced by a path that specifies the entry point(s) for which you wish to generate code. For a set of test files in test, this would typically be tool/builder.dart test/*_test.dart.

It should be noted that you need to generate code for the same set of entry points every time you run builder.dart. This is because the build framework stores data about the code generation in a single database in the directory .dart_tool, so you will get complaints about inconsistencies if you switch from generating code for web/myProgram.dart to generating code for web/myOtherProgram.dart. If and when you need to generate code for another set of programs, delete all files named *.reflectable.dart, and delete the whole directory .dart_tool.

Again, the approach where you are using your own builder.dart to generate the code is more flexible, but the recommended standard approach is to use pub run build_runner ....

Note that it is necessary to perform the code generation step if you use reflectable directly or indirectly by depending on a package that uses reflectable. Even in the indirect case there may (typically will!) be a need to generate code based on files in your package.

Conversely, if you are writing a package which uses reflectable and is expected to be used by clients, please make it explicit that such clients must run this step in order to obtain the generated code for each root library.

The generated file contains the data needed for reflection, and a declaration of the top-level function initializeReflectable, which will initialize the reflection framework and which must be called before any reflective features are used.

For a more advanced example, you could look at serialize_test.dart and its library, where the base of a serialization framework is implemented; or you could look at meta_reflectors_test.dart and the libraries it imports, which illustrates how reflectable can be used to dynamically make a choice among several kinds of reflection, and how to eliminate several kinds of static dependencies among libraries.

Known limitations #

Several parts of the library have not yet been implemented. In particular, the following parts are still incomplete:

  • Reflection on functions/closures. We do not have the required primitives to support this feature, so it is expected to remain unsupported for a while. There is support for one case: When a function type is given a name with typedef it is possible to use that name as a type annotation, say, on a method parameter or as a return type, and then reflectedTypeCapability will make it possible to get a corresponding reflectedType and dynamicReflectedType. For non-generic function types this will also work with anonymous (inline) function types like void Function(int).

  • Private declarations. There is currently almost no support for reflection on private declarations, as this would require special support from the runtime for accessing private names from other libraries. As an example of a case where there is some support, library mirrors can deliver class mirrors for private classes, and instanceMembers includes public members inherited from private superclasses. But in the vast majority of situations, private declarations are not supported.

  • uri's of libraries. The transformer framework does not give us access to good uri's of libraries, so these are currently only partially supported: A unique uri containing the name given in the library directive (if any) is generated for each library; this means that equality tests will work, and the toString() of a uri will be somewhat human readable. But this kind of uri does not give any information about the location of a corresponding file on disk.

  • Type arguments of generic types are only supported in some statically resolved cases, because we do not have the primitives required for a general implementation. E.g., when it is known statically that a given list of actual type arguments is empty then the empty list is returned. Moreover, if a type annotation contains only types which are fully resolved statically, it is possible to get these type arguments, as mirrors or as instances of Type using various reflected type features. An example is shown below.

  • The mirror method libraryDependencies has not yet been implemented.

Here is an example illustrating the partial support for type arguments:

class Reflector extends Reflectable {
  const Reflector()
      : super(invokingCapability, typingCapability, reflectedTypeCapability);

const reflector = Reflector();

class A<X> {
  A<B> ab;
  A<X> ax;

class B {}

main() {
  ClassMirror aMirror = reflector.reflectType(A);
  final declarations = aMirror.declarations;
  VariableMirror abMirror = declarations['ab'];
  VariableMirror axMirror = declarations['ax'];
  print(abMirror.type.typeArguments[0].reflectedType); // Prints 'B'.
  print(abMirror.type.reflectedTypeArguments[0] == B); // Prints 'true'.
  try {
    print(axMirror.type.typeArguments[0]); // Throws 'UnimplementedError'.
    print("Not reached");
  } on UnimplementedError catch (_) {
    print("As expected: Could not get type mirror for type argument.");
  try {
    axMirror.type.reflectedTypeArguments[0]; // Throws 'UnimplementedError'.
    print("Not reached");
  } on UnimplementedError catch (_) {
    print("As expected: Could not get reflected type argument.");

// Output:
//   B
//   true
//   As expected: Could not get type mirror for type argument.
//   As expected: Could not get reflected type argument.

As the example above illustrates, we can invoke reflectedTypeArguments on the mirror of the type annotation of ai and get <Type>[int], because that type argument list is statically resolved, but we cannot do it with ax because X will have different values at different occasions at run time (that is, it is not fully resolved statically).

Similarly, it is not supported to obtain the actual type arguments for an existing instance; e.g., if we have an expression of type Iterable then we may evaluate it and get an instance x of List<int>. We can test x is List<num> and get true, and we can get false for x is List<double>, but we cannot directly extract the type argument (int) using reflection. That is because it can only be done with support for some primitives (that is, built-in operations with special powers) that do not exist today.

Feature requests and bug reports #

Please file feature requests and bugs using the github issue tracker for this repository.

2.2.4 #

  • Eliminate dependency on package package_resolver (which is deprecated).

2.2.3 #

  • Introduce support for the type void as a reified type.

2.2.2 #

  • Generate code which will not cause implementation_imports diagnostics.

2.2.1+2 #

  • Update reflectable to work with analyzer 0.39.4 and up to 0.40.0.

2.2.1+1 #

  • Restricting analyzer version to <= 0.39.3, because 0.39.3 contains a breaking change in the parameter list of a constructor.

2.2.1 #

  • Fix a bug concerned with the ordering of named parameters in a constructor declaration.
  • Update reflectable to use package analyzer version <0.40.0.
  • Ensure that generated code is lint free with package pedantic 1.9.0.
  • Make reflectable itself lint free with package pedantic 1.9.0.

2.2.0 #

  • Adjust implementation to satisfy 'pedantic' lints. The generated code does this as well, except that some const modifiers are generated even though they could be omitted (an // ignore_for_file comment is generated such that the linter does not complain about this). Upgrade dependencies to allow using analyzer 0.38.5, and current versions of many other packages.

2.1.0 #

  • Code generator rewritten in order to work with changes in the analyzer APIs, enabling the use of analyzer version 0.37.0 (and newer versions of many other packages), which addresses issue #173. See issue #180 about missing support for two features: This affects code in platform libraries (that is, libraries imported with 'dart:...' except 'dart:ui'). If a declaration in a platform library has metadata, a query for this metadata using DeclarationMirror.metadata will return null. Also, if a constructor in a platform library has a parameter with a default value, and that parameter is omitted in a reflective invocation, the value passed will be null rather than the declared value. This is a bug, but it is blocked on getting access to AST nodes in platform libraries from the resolver provided by build.

2.0.12 #

  • Follow-up bug fix related to #170: Corrected ParameterMirror.defaultValue for initializing formals.

2.0.11 #

  • Bug fix #170: Default values for initializing formals are now included when generating function literals for newInstance.

2.0.10+1 #

  • Lint fixes (e.g., T x; rather than T x = null;).

2.0.10 #

  • Updated dependency to allow using source_span 1.5.3.

2.0.9 #

  • Updated dependency to allow using analyzer 0.34.

2.0.8+1 #

  • Corrected the email address listed in pubspec.yaml for Dart Team.

2.0.8 #

  • Fix version conflict #153: Updated version constraints on analyzer, build, build_runner, and test. Ported reflectable_builder.dart to work with new build API.

2.0.7 #

  • Bug fix #132: We used to generate terms like prefix2.di.inject in order to denote a top level declaration named inject, but that's an error because di is an import prefix from client code. We now strip off such prefixes (yielding prefix2.inject) in the cases reported in issue #132.

2.0.6 #

  • Adjusts an implementation class (MixinApplication) such that a compile-time error occurring with analyzer 0.32.5 is avoided.

2.0.5 #

  • Enhancement of the support for reflection on type arguments, covering cases where a type annotation is a parameterized type where all type arguments are resolved statically (e.g., List<int> f();). We (still) do not support cases where one or more type arguments are or contain type variables from an enclosing function or class (like the type of the formal parameter to List.addAll: List<E>), and with such type arguments a dynamic error is raised if an attempt is made to access it. Similarly, we (still) do not support extracting the value of the actual type arguments for an instance of a generic class (e.g., for a given list, we cannot obtain the precise value of the actual type argument; we can test things like myList is List<num> and myList is List<String> without reflection at all, but that only reveals an upper bound, not the precise value of the type argument, and we cannot get that precise value without support for some additional primitives).

  • The build.yaml file in reflectable was adjusted such that a much larger set of files are included for code generation. This means that we will err on the side of generating code for too many files rather than too few, but this choice seems to be more user-friendly. Developers who get irritated about seeing warnings like "This reflector does not match anything" (which is a likely outcome for code generation applied to some arbitrary library which is not an entry point) can then add a build.yaml file specifying more precisely which libraries to generate code for.

2.0.4 #

  • Null error bug fix.

2.0.3 #

A stable version of Dart 2 has been released at this point. This version of reflectable contains a rather substantial number of changes needed in order to make it possible to use this package with the current Dart 2 tools, and under the associated version constraints.

  • Eliminates the use of package barback (which is now deprecated). This change requires many changes in the implementation, but it should not give rise to incompatibilities for clients of reflectable.

  • Updates many version dependencies: analyzer, build_resolvers, build_config, build_runner, and test, in order to enable the use of Dart 2 tools.

  • Changes a handful of implementation details such that every downcast is concretely justified. Removed new from the implementation (but not from generated code), because code generation must anyway use Dart 2, but generated code may still need to run as Dart 1.

  • Improves code generation ERROR, WARNING, and INFO messages such that it includes a precise source code location.

  • Now includes lib/main.dart among possible build targets, because Flutter uses that as the standard entry point.

2.0.2 #

  • Update the SDK version constraint to 3.0.0 to satisfy Dart 2 requirements.

2.0.1 #

  • This version is a tiny update: It solves a version problem by changing some package dependencies.

2.0.0 #

This version is updated for Dart 2, to the extent that this is possible at this point (a stable version of Dart 2 has not yet been released). Minor updates will be used to track the language updates as needed, so a dependency on reflectable version ^2.0.0 should work for Dart 2.

  • Update version number, prepare package for being published.

2.0.0-dev.3.0 #

  • Now supports client packages using commands like pub run build_runner test to generate code and run tests.
  • Added support for generating code to obtain the Type value of function types (including the new inline function types like String Function(int)).
  • Fixed bugs associated with error handling: In several situations where the build process would get stuck indefinitely, it will now terminate with the intended error message.
  • Added note to that generated code should not be published (it should be regenerated, such that it matches the current version of all dependencies).
  • Added 'dart:ui' to the set of platform libraries that reflectable will recognize (and potentially import). This will only work on Flutter, but there would not be any references to 'dart:ui' for any non-Flutter program, unless it is already broken in other ways.

2.0.0-dev.2.0 #

  • Removed bin/reflectable_transformer.dart, which is obsolete.
  • Changed TestTransform to require its 3rd constructor argument, because there is no default way to obtain the path to '.packages'.
  • Generated files are now placed in 'test' rather than 'build/test'; adjusted 'test_transform.dart' to work with that setup, and enable pub run test.

2.0.0-dev.1.0 #

This version is a pre-release of the version 2.0.0 which makes all the changes described below. Henceforth, reflectable will be based on code generation using build rather than a pub transformer, because transformers will not be supported in the future.

  • Switched to a new technology stack: Reflectable no longer provides a pub transformer, it uses package build to generate code as a separate step. This is a breaking change for every program using reflectable because it requires a different workflow, it requires the generated code to be imported explicitly by the root library (the one that contains the main function), and it requires invocation of initializeReflectable() at the beginning of main. To see the commands in this new workflow, please consult

1.0.4 #

  • Updated version constraint on analyzer to include versions ^0.30.0. Note that this forces a lower bound of 0.30.0 because of a breaking change in the analyzer.

1.0.3 #

  • Updated version constraint on dart_style.

1.0.2 #

  • Bug fix, handling the case where prefix is null on a library mirror, and the case where targetLibrary is null on a library dependency mirror.

1.0.1 #

  • Updates analyzer and code_transformers dependencies.
  • As a consequence of these version updates, changes a method signature and deletes a method (overriding a previously deprecated, now deleted method). These changes should not affect clients of this package.

1.0.0 #

  • Updates documentation about capabilities required for each method.
  • Potentially breaking bug fix: Several mirror methods perform more strict checks on capabilities, to make them match the documented requirements. In particular, LibraryMirror.libraryDependencies requires a libraryCapability; ClosureMirror.apply requires an InstanceInvokeCapability; ParameterMirror.hasDefaultValue, ParameterMirror.defaultValue, MethodMirror.parameters, GetterMirror.parameters, and SetterMirror.parameters require a DeclarationsCapability; TypeMirror.isOriginalDeclaration, TypeMirror.typeArguments, ClassMirror.isAssignableTo, TypeVariableMirror.isAssignableTo and TypeVariableMirror.isSubtypeOf require a TypeRelationsCapability; and ClassMirror.dynamicReflectedType and VariableMirror.reflectedType require a ReflectedTypeCapability.
  • Updates tests to work with --no-packages-dir.
  • Deprecates NameCapability, nameCapability, ClassifyCapability, and classifyCapability; these capabilities are now always enabled.
  • Uses more strict typing in generated code: List and Map literals will now consistently include type arguments. This is rarely detectable in client code, but could for instance be detected in some situations with complex metadata.
  • Uses more strict typing in the implementation, in order to pass strong mode checks.

0.5.4 #

  • Potentially breaking bug fix: Several additional mirror methods documented to require a typeRelationsCapability will now actually require it. Concretely, this affects the methods typeVariables, typeArguments, superclass, superinterfaces, mixin, isSubclassOf, isAssignableTo, isSubtypeOf, originalDeclaration. Programs relying on the previous (incorrect) behavior may need to have the relevant reflectors extended with a typeRelationsCapability. This change also enables throwing an error which blames the missing capability rather than incorrectly blaming lack of coverage for a specific class. This fixes issue 77.
  • Adds constant resolution requests for metadata such that some spurious 'This reflector does not match anything' events are avoided; fixes issue 82.
  • Corrects treatment of metadata with enum values, fixing issue 80.
  • Adds two missing package dependencies, fixing issue 81.

0.5.3 #

  • Eliminates the binding to analyzer 0.27.1, using ^0.27.2 instead; also uses code_transformers ^0.4.1.
  • Introduces support for entry point globbing; for more information please consult commit 8936f98.

0.5.2 #

  • Potentially breaking bug fix: In transformed code, superinterfaces used to be callable even without a typeRelationsCapability. That capability is now required (as it should be according to the documentation) and this will break programs that rely on the old, incorrect behavior.
  • Adds support for recognizing a const field as a reflector (e.g., class C can be covered by having @SomeClass.aConstField as metadata on C).
  • Fixes bug: misleading error messages from isSubtypeOf and isAssignableTo corrected.
  • Fixes bug: now named constructors can be used in metadata (e.g., var x; can be used to get reflective support for x).
  • Fixes bug: certain external function type mirrors seem to be unequal to themselves, which caused an infinite loop; now that case is handled.
  • Adds a stand-alone version of the transformer; for more information please consult the main comment on commit 8f90cb9.
  • Fixes bug: some private names could occur in generated code; this situation is now detected more consistently and transformation fails.
  • The documentation now clearly states that it is not supported to use reflectable in untransformed mode with dart2js generated code.
  • Adds a small corner of support for function types: A typedef can be used to give a function type a name, and such a type can be used as a type annotation (say, for a method parameter) for which it is possible to obtain a mirror, and that type hasReflectedType.
  • Fixes bug: in the case where a reflector does not match anything at all there used to be a null error; now that is handled, and a warning is emitted.
  • Switches from using an AggregateTransform to using a plain Transform for all transformations; this reduces the number of redundant transformations performed in the context of pub serve.
  • Adds extra tests such that line coverage in the transformer is again complete.
  • Fixes bug: hasReflectedType used to incorrectly return true in some cases where a type variable was used in a nested generic type instantiation.
  • Fixes bugs associated with anonymous mixin applications involving type arguments.
  • Fixes bug: several error messages claimed 'no such method' where they should claim 'no such constructor' etc.
  • Fixes bug: it is now possible to invoke a constructor in an abstract class reflectively, as long as it is a factory.
  • List receives some constructor arguments with default values which are different on different platforms, and the analyzer reports that there are no default values; this release introduces a special case for that.
  • Fixes bug: some constructors of native classes were omitted, are now available like other members.

0.5.1 #

  • Changes the version constraint on analyzer to 0.27.1, to avoid an issue with version 0.27.1+1 which breaks all reflectable transformations. Note that this is a tight constraint (just one version allowed), but currently all other versions above 0.27.0 will fail so there is no point in trying them.
  • Bug fix: The transformer now treats the entry points as a set such that duplicates are eliminated; duplicates of entry points are not useful, and they can trigger an infinite loop if present.

0.5.0 #

  • Breaking: The methods hasBestEffortReflectedType and bestEffortReflectedType are now deprecated. They will be removed in the next published version.
  • Breaking: Implements a new semantics for no-such-method situations: When a reflectable invocation (invoke, invokeGetter, invokeSetter, newInstance, delegate) fails due to an unknown selector or an argument list with the wrong shape, a ReflectableNoSuchMethodError is thrown. (In particular, noSuchMethod is not invoked, and no NoSuchMethodError is thrown). For more details, please consult the capability design document near occurrences of 'no-such-method'.
  • Fixes issue 51, which is concerned with coverage of getters/setters for variables inherited from non-covered classes.
  • Breaking: Changes coverage such that it requires a SuperclassQuantifyCapability in order to include support for an anonymous mixin application (like A with M in class B extends A with M..). Such mixin applications used to be included even without the SuperclassQuantifyCapability, but that was an anomaly.
  • Breaking: Changes the semantics of superclass to strictly follow the documentation: It is now required to have a TypeRelationsCapability in order to perform superclass, even in the cases where this yields a mixin application.
  • Breaking: Changes the semantics of instanceMembers and staticMembers to strictly follow the documentation: It is now required to have a DeclarationsCapability in order to perform these methods.
  • Breaking: Eliminates the non-trivial upper bound on the version of the analyzer package (because the constant evaluation issue has been resolved). The analyzer dependency is now '^0.27.0'. Switches to code_transformers version '^0.3.0'.
  • Updates the capability design document to document the new treatment of no-such-method situations.
  • Implements isSubtypeOf and isAssignableTo for type mirrors.
  • Fixes issue 48, which is about wrong code generation involving mixin applications.
  • Implements delegate on instance mirrors, and adds a delegateCapability to enable it. The reason why this requires a separate capability is that the cost of storing maps between strings and symbols needed by delegate is non-trivial.
  • Changes code generation to avoid generating code for some unused mirrors.
  • Fixes bug which prevented recognition of some forms of metadata during metadata based capability checking.

0.4.0 #

  • Changes the representation of reflected types such that duplication of Type expressions is avoided (by using indices into a shared list).
  • Adds methods dynamicReflectedType and hasDynamicReflectedType to several mirror classes, yielding the erased version of the reflected type (for List<int> it would return List<dynamic>, i.e., List). This method is capable of returning a result in some cases where reflectedType fails.
  • Corrects the behavior of methods reflectedType and hasReflectedType, such that reflectedType returns an instantiated generic class when that is appropriate, and hasReflectedType returns false in some cases where it used to return true, because the correct instantiated generic class cannot be obtained.
  • Adds method bestEffortReflectedType which will use reflectedType and dynamicReflectedType to obtain a reflected type if at all possible (though with a less precise specification, because it may be one or the other). Adds method hasBestEffortReflectedType to go with it. This pair of methods resembles the 0.3.3 and earlier semantics of reflectedType.

The version number is stepped up to 0.4.0 because reflectedType behaves differently now than it did in 0.3.3 and earlier, which turned out to break some programs. In some cases the best reaction may be to replace invocations of reflectedType and hasReflectedType by the corresponding "best effort" methods, but it may also be better to use both the reflectedType and the dynamicReflectedType method pairs, taking the precise semantics into account when using the returned result.

Note that version 0.3.4 also deals with reflectedType in a stricter way than 0.3.3 and earlier versions, but at that point the changes were considered to be bug fixes or implementations of missing features.

0.3.4 #

  • NB Adds a non-trivial upper version constraint on analyzer in order to require version 0.26.1+14 or older. This is necessary because newer versions of analyzer have changed in ways that are incompatible with reflectable in several ways. We expect to be able to allow using the newest version of analyzer again soon.
  • Implements support for moving additional kinds of expressions (for argument default values and metadata), esp. when they use a library prefix (such as @myLib.myMetadata).
  • Adds test cases for previously untested capabilities (NewInstanceMetaCapability and TypingCapability).
  • Fixes bug where pre-transform check would attempt to use null but should instead throw NoSuchCapabilityError.
  • Adds missing checks in pre-transform code (e.g., checking that a LibraryCapability is available when performing a top-level invocation).
  • Corrects inconsistency among the type hierarchies for pre/post-transform capabilities (which caused the post-transform code to act incorrectly).
  • Corrects treatment of TypingCapability, adjusted it to include LibraryCapability.
  • Introduces UnreachableError and adjusted error handling to throw this in all cases where a location should never be reached.
  • Several '' files updated to match the current status.
  • A couple of smaller unimplemented methods implemented.
  • Eliminates many of the 'Missing entry point' messages: If it is specified that an entry point 'web/foo.dart' must be transformed, but no such asset is provided to the transformer, then the warning is only emitted if the file does not exist (with pub build test, 'web/foo.dart' is not provided to the transformer, but that is not a problem).
  • Corrects the bug that typeRelationsCapability was sometimes not required with certain operations (including superclass), even though the documentation states that it is required. Similarly, a TypeCapability is now required in a few extra cases where it should be required.
  • Correct the cyclic-dependency bug which previously made 'expanding_generics_test.dart' fail.
  • Adds support for enum classes.
  • Implement support for all the trivial parts of genericity: empty lists of type arguments are now delivered rather than throwing UnimplementedError, and static information like type variables (that is, formals) is supported.
  • Implement several missing class members, including isEnum, isPrivate, isOriginalDeclaration, originalDeclaration.
  • Correct several bugs in the implementation of LibraryMirror.
  • Correct several bugs with owner.
  • Implement several features for top-level entities, especially variables.
  • Correct several incorrect type annotations (e.g., List required, but only Iterable justified).
  • Implement simple code coverage support.

0.3.3 #

  • Update many DartDoc comments in 'capability.dart'.
  • Update the document The Design of Reflectable Capabilities to match the current selection of quantifiers and their semantics.
  • Add very limited support for private classes: They are preserved such that iteration over all superclasses will work even if some of them are private, and private class mirrors are included in declarations of library mirrors. However, it is not possible to reflect on an instance of a private class, to create new instances with newInstance, nor to call its static methods.
  • Fix bug where some private names were used in generated code (which makes subsequent compilation fail).
  • Add option to format the generated code (off by default).
  • Add correspondingSetterQuantifyCapability, which will add the corresponding setter for each already included explicitly declared getter.
  • Change generated code: Eliminate many invocations of new UnmodifiableListView.., replace many plain list literals by const list literals, for better startup time and more redundancy elimination.
  • Fix bug where an InvokingMetaCapability was treated as a NewInstanceMetaCapability.
  • Fix bugs in the publication support script.

0.3.2 #

  • Introduce reflectedTypeCapability which enables methods reflectedType on variable and parameter mirrors, and reflectedReturnType on method mirrors. This enables limited access to type annotations while avoiding the generation of many class mirrors.
  • Introduce Reflectable.getInstance which delivers the canonical instance of any given reflector class which is being used in the current program. An example shows how this enables "meta-reflection".
  • Fixed bugs in methods isAbstract, isSynthetic; fixed bug in selection of supported members of library mirrors; and implemented methods libraries and declarations for library mirrors; and fixed several other library related bugs.

0.3.1 #

  • Fix bug where metadata was searched the same way for invocation and for declarations with InstanceInvokeMetaCapability (invocation must traverse superclasses).
  • Fix bug where some libraries were imported into generated code, even though they cannot be imported (private to core).
  • Fix bugs in publication support script.

0.3.0 #

  • Breaking: Add support for type annotation quantification. This is a breaking change: we used to do that implicitly, but that is expensive, and now it is only available on request.
  • Change the way the set of supported classes are computed.
  • Fix crash when transforming certain dart:html classes.
  • Fix memory leak from the transformer.

0.2.1 #

  • Recognize private identifier constants as metadata in certain cases.
  • Bump required SDK version in pubspec.yaml.
  • Correct generation of imports of the original entry point.
  • Fix issues with the computation of static members.
  • Allows the metadata capabilities to recognize any subtype of the given type.

0.2.0 #

  • Breaking: Enforces the use of a TypeCapability as specified in the design document, and makes it a supertype of several other capabilities such that it is automatically included with, e.g., declarationsCapability.
  • Fixed homepage link in pubspec
  • Fix several bug with mixins in the transformer.
  • Add excludeUpperBound flag to SuperClassQuantifyCapability.
  • Use a static initializer in the generated code which helps avoiding a stack overflow.

0.1.5 #

  • Support for return types of getters and setters.
  • Support for superTypeQuantifyCapability.
  • Fix bug in the mirror-based implementation's collection of classes that could lead to infinite loops.
  • Fix bug related to generating code for operator~ in the transformer.
  • Avoid crashing the transformer when an entry-point has no member named main

0.1.4 #

  • Support for subtype quantification in transformed code.
  • Code generation bugs fixed; metadata/library related bugs fixed.
  • Faster version of test procedure.

0.1.3 #

  • Non-transformed code supports subTypeQuantifyCapability
  • Transformer implements .superinterfaces
  • Transformer implements .mixin
  • Transformer implements reflection on libraries.
  • Better support for default values in transformed code.

0.1.2 #

  • Our tests started failing because of a version conflict introduced by an update to code_transformers. Changed pubspec.yaml to avoid the conflict.
  • Made changes to avoid deprecated features in the new version of analyzer.
  • Implemented support for implicit accessors (setters, getters).
  • Implemented support for staticMembers on ClassMirror.

0.1.1 #

  • Transformer implements .type of fields and parameters.
  • Transformer has support for main function that is not in the entry-point file.
  • Transformer supports async main returning a Future.
  • Other bug fixes...

0.1.0 #

  • First published release.

0.0.1 #

  • Initial project creation


// Copyright (c) 2018, the Dart Team. All rights reserved. Use of this
// source code is governed by a BSD-style license that can be found in
// the LICENSE file.

// Try out some reflective invocations.
// Build with `cd ..; pub run build_runner build example`.

import 'package:reflectable/reflectable.dart';
import 'example.reflectable.dart';

class MyReflectable extends Reflectable {
  const MyReflectable() : super(invokingCapability);

const myReflectable = MyReflectable();

class A {
  int arg0() => 42;
  int arg1(int x) => x - 42;
  int arg1to3(int x, int y, [int z = 0, w]) => x + y + z * 42;
  int argNamed(int x, int y, {int z = 42}) => x + y - z;
  int operator +(x) => 42 + x;
  int operator [](x) => 42 + x;
  void operator []=(x, v) { f = x + v; }
  int operator -() => -f;
  int operator ~() => f + 2;

  int f = 0;

  static int noArguments() => 42;
  static int oneArgument(x) => x - 42;
  static int optionalArguments(x, y, [z = 0, w]) => x + y + z * 42;
  static int namedArguments(int x, int y, {int z = 42}) => x + y - z;

main() {
  // The program execution must start run this initialization before
  // any reflective features can be used.

  // Get hold of a few mirrors.
  A instance = A();
  InstanceMirror instanceMirror = myReflectable.reflect(instance);
  ClassMirror classMirror = myReflectable.reflectType(A);

  // Invocations of methods accepting positional arguments (printing '42').
  print(instanceMirror.invoke("arg0", []));
  print(instanceMirror.invoke("arg1", [84]));
  print(instanceMirror.invoke("arg1to3", [40, 2]));
  print(instanceMirror.invoke("arg1to3", [1, -1, 1]));
  print(instanceMirror.invoke("arg1to3", [21, 21, 0, "foo"]));
  // Invocations of methods accepting named arguments (printing '42').
  print(instanceMirror.invoke("argNamed", [55, 29]));
  print(instanceMirror.invoke("argNamed", [21, 21], {#z: 0}));

  // Invocations of operators.
  print(instanceMirror.invoke("+", [42])); // '84'.
  print(instanceMirror.invoke("[]", [42])); // '84'.
  instanceMirror.invoke("[]=", [1, 2]);
  print(instance.f); // '3'.
  print(instanceMirror.invoke("unary-", [])); // '-3'.
  print(instanceMirror.invoke("~", [])); // '5'.

  // Similar invocations on static methods (printing '42').
  print(classMirror.invoke("noArguments", []));
  print(classMirror.invoke("oneArgument", [84]));
  print(classMirror.invoke("optionalArguments", [40, 2]));
  print(classMirror.invoke("optionalArguments", [1, -1, 1]));
  print(classMirror.invoke("optionalArguments", [21, 21, 0, "foo"]));
  print(classMirror.invoke("namedArguments", [55, 29]));
  print(classMirror.invoke("namedArguments", [21, 21], {#z: 0}));

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:

  reflectable: ^2.2.4

2. Install it

You can install packages from the command line:

with pub:

$ pub get

with Flutter:

$ flutter pub get

Alternatively, your editor might support pub get or flutter pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:

import 'package:reflectable/reflectable.dart';
Describes how popular the package is relative to other packages. [more]
Code health derived from static analysis. [more]
Reflects how tidy and up-to-date the package is. [more]
Weighted score of the above. [more]
Learn more about scoring.

We analyzed this package on Mar 31, 2020, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.7.1
  • pana: 0.13.6

Maintenance issues and suggestions

Support latest dependencies. (-10 points)

The version constraint in pubspec.yaml does not support the latest published versions for 1 dependency (build_runner_core).


Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.3.0 <3.0.0
analyzer 0.39.4 0.39.4
build ^1.2.0 1.2.2
build_config ^0.4.0 0.4.2
build_resolvers ^1.2.0 1.3.3
build_runner ^1.7.0 1.8.0 1.8.1
build_runner_core ^4.1.0 4.5.3 5.0.0
dart_style ^1.3.0 1.3.3
glob ^1.2.0 1.2.0
logging ^0.11.0 0.11.4
package_config ^1.1.0 1.9.3
path ^1.6.0 1.6.4
source_span ^1.5.0 1.7.0
Transitive dependencies
_fe_analyzer_shared 1.0.3
args 1.6.0
async 2.4.1
build_daemon 2.1.4
built_collection 4.3.2
built_value 7.0.9
charcode 1.1.3
checked_yaml 1.0.2
code_builder 3.2.1
collection 1.14.12
convert 2.1.1
crypto 2.1.4
csslib 0.16.1
fixnum 0.10.11
graphs 0.2.0
html 0.14.0+3
http 0.12.0+4
http_multi_server 2.2.0
http_parser 3.1.4
io 0.3.3
js 0.6.1+1
json_annotation 3.0.1
matcher 0.12.6
meta 1.1.8
mime 0.9.6+3
node_interop 1.0.3
node_io 1.0.1+2
package_resolver 1.0.10
pool 1.4.0
pub_semver 1.4.4
pubspec_parse 0.1.5
quiver 2.1.3
shelf 0.7.5
shelf_web_socket 0.2.3
stack_trace 1.9.3
stream_channel 2.0.0
stream_transform 1.2.0
string_scanner 1.0.5
term_glyph 1.1.0
timing 0.1.1+2
typed_data 1.1.6
watcher 0.9.7+14
web_socket_channel 1.1.0
yaml 2.2.0
Dev dependencies
build_test ^0.10.0
pedantic ^1.8.0 1.9.0
test ^1.9.0