Reflectable

repository·master·Indexed 18 days ago

https://github.com/google/reflectable.dart

A capability-based reflection system for Dart designed for environments where dart:mirrors is not supported, such as Flutter and the web. It uses a combination of the reflectable core package and the reflectable_builder code generator to provide static, explicit reflection capabilities while minimizing runtime resource requirements.

Tokens
20.2K
Snippets
15
Records
34
Agent score
63%

What's inside reflectable

  1. Overview of the Reflectable ecosystem

    master

    The reflectable ecosystem provides a way to implement reflection in Dart without relying on the dart:mirrors library, which is essential for environments like Flutter where dart:mirrors is unavailable. The ecosystem consists of three main components:

    1. reflectable: The core package that provides reflection capabilities. It uses a capability-based system to allow developers to control exactly how much reflection support is enabled, optimizing for performance and tree-shaking.
    2. reflectable_builder: A code generation package. Since reflectable does not use dart:mirrors, it requires generated code to perform reflection tasks. You use this builder to generate that necessary metadata.
    3. test_reflectable: A repository containing test cases and practical examples demonstrating how to use the core packages in real-world scenarios.
  2. Use Reflectable Builder for code generation

    master

    The reflectable_builder package is the code generator for the reflectable package. It is used to generate the necessary reflection metadata and code required for reflectable to function in environments where standard Dart reflection (like dart:mirrors) is unavailable (e.g., Flutter or web).

    For core usage instructions, API details, and how to annotate your classes, refer to the main reflectable documentation.

  3. What is Reflectable and how does it work?

    master

    Reflectable is a Dart package that provides a way to use reflection while minimizing runtime resource requirements. Unlike dart:mirrors, which provides full dynamic reflection, Reflectable requires you to explicitly and statically specify the required reflection features, known as capabilities.

    Core Concepts

    • Capabilities: These are specific reflective features (e.g., invokingCapability) that you request. Reflection is only allowed for the capabilities you specify; attempting to use an unsupported feature results in a NoSuchCapabilityError.
    • Reflector: Reflection is accessed via a subclass of Reflectable. You define a custom reflector class, specify its capabilities in the super-initializer, and then use an instance of this class to perform reflective operations.
    • Coverage: A class is 'covered' by a reflector if it is annotated with that reflector (e.g., @reflector) or if it is a subtype of a class that is annotated.
    • Code Generation: Because the required reflection support is known at compile time, the package uses reflectable_builder to generate specialized code that satisfies your specific capability requirements.
  4. Known limitations of Reflectable

    master

    Reflectable has several current limitations regarding reflection capabilities. Users should be aware of the following constraints:

    • Functions/Closures: Reflection on functions is generally unsupported. The exception is when a function type is given a name via typedef; you can then use that name as a type annotation to access reflectedType and dynamicReflectedType via reflectedTypeCapability.
    • Private Declarations: Reflection on private declarations is largely unsupported because the runtime does not allow accessing private names from other libraries. However, library mirrors can provide class mirrors for private classes, and instanceMembers includes public members inherited from private superclasses.
    • Library URIs: Library URIs are only partially supported. While unique URIs are generated based on the library directive (allowing for equality tests and human-readable toString() output), they do not provide the file location on disk.
    • Generic Type Arguments: Type arguments are only supported in cases that are statically resolvable. If a type argument is fully resolved statically, you can retrieve it via mirrors or Type instances. If the type argument depends on runtime values (e.g., a generic parameter X in class A<X>), attempting to access it will throw an UnimplementedError.
    • Instance Type Arguments: You cannot extract actual type arguments from an existing instance (e.g., extracting int from an instance of List<int>) due to a lack of required runtime primitives.
  5. Select reflection capabilities using RegExp and MetadataClass

    master

    When defining reflection capabilities in reflectable, you can control which entities (methods, getters, etc.) are included using two primary selection mechanisms:

    1. Pattern Matching with RegExp: You can pass a String representing a regular expression as an argument to a capability. This allows you to include only entities that match the pattern. If the argument is omitted (empty RegExp), all entities in that category are included.
    2. Decentralized Selection with MetadataClass: You can pass a Type (representing a MetadataClass) to a capability. An entity is included if and only if it is annotated with metadata that is a subtype of the provided MetadataClass. This allows you to mark specific members for reflection using existing or custom annotations.

    Note: The MetadataClass does not need to be part of the reflectable package; it can be any class used for metadata (e.g., for serialization).

  6. How reflection capabilities are specified

    master

    Reflection capabilities in reflectable are specified by building immutable trees of const objects. These objects follow a subtype hierarchy rooted in the class ReflectCapability (found in package:reflectable/capability.dart).

    Mental Model: The Reflectable Capability Language

    Think of these capability trees as Abstract Syntax Trees (ASTs) for a domain-specific language called the reflectable capability language.

    • Structure: You build the tree by nesting instances of ReflectCapability subtypes. Because these are const values, they are immutable and contain no methods.
    • Semantics: The actual
  7. Use grouping tokens for concise capability selection

    master

    To avoid verbose syntax when requesting broad reflection support, use the following grouping tokens:

    • invoking([RegExp]): Includes instanceInvoke([RegExp]), staticInvoke([RegExp]), and newInstance([RegExp]).
    • invokingMeta(MetadataClass): Includes instanceInvokeMeta(MetadataClass), staticInvokeMeta(MetadataClass), and newInstanceMeta(MetadataClass).
    • typing: A shorthand to request all structural information capabilities: type, name, classify, metadata, typeRelations, owner, declarations, uri, and libraryDependencies.
    | **Group** | **Meaning** |
    | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------reflectable capability language grouping tokens |
    | `invoking([`*`RegExp`*`])` | `instanceInvoke([`*`RegExp`*`])`, `staticInvoke([`*`RegExp`*`])`, `newInstance([`*`RegExp`*`])` |
    | `invokingMeta(`*`MetadataClass`*`)` | `instanceInvokeMeta(`*`MetadataClass`*`)`, `staticInvokeMeta(`*`MetadataClass`*`)`, `newInstanceMeta(`*`MetadataClass`*`)` |
    | `typing` | `type`, `name`, `classify`, `metadata`, `typeRelations`, `owner`, `declarations`, `uri`, `libraryDependencies` |
  8. Understand automatic capability inclusion via subtyping

    master

    Reflectable uses a subtype structure among capability classes to automatically include related capabilities. If you specify a capability C1 that is a subtype of C0, including C1 automatically implies the inclusion of C0.

    For example, specifying the declarations capability automatically includes the type capability, because declarations is useless without the ability to obtain the types of the members being declared.

  9. Understand Reflection Capability Design Semantics

    master

    Reflectable uses a capability-based system to specify reflection support. The design follows two key mathematical properties:

    1. Monotonicity: Adding more reflection specifications can only increase the amount of reflection support available; it can never withdraw or prevent features requested by existing specifications.
    2. Idempotency: Requesting the same feature or overlapping feature sets multiple times is harmless and has no additional effect.

    This allows for modularity: if a piece of code requires a specific reflection capability S, you can trust that S will be present, even if other parts of the program add even more capabilities.

  10. Specify Mirror API Based Capabilities

    master

    Mirror API based capabilities allow you to control which methods on mirror classes (like InstanceMirror or ClassMirror) are enabled. This is useful for minimizing the reflection footprint.

    There are two levels of API specification:

    • Direct Method Support: Turning on support for specific individual methods. For example, you can enable InstanceMirror.invoke without enabling ClassMirror.invoke.
    • Predicate-based Refinement: Specifying allowable argument values for API methods. You can provide a predicate to filter which methods are supported. For example, you could enable InstanceMirror.invoke only for methods whose names satisfy a specific pattern (e.g., names ending in ...Test).

    If an unsupported method is called on a mirror, an exception is thrown.

  11. Understanding the ReflectCapability hierarchy

    master

    The ReflectCapability class serves as the root for all reflection capability specifications.

    Key characteristics of the hierarchy:

    • Sealed Hierarchy: The set of subtypes under ReflectCapability is fixed. This ensures that the package's code generator (the "translator") can always handle any capability tree you build. An unknown subtype would result in a lack of defined semantics.
    • Immutable ASTs: Capabilities are used as const values to represent expressions. They do not have methods (other than those from Object) and cannot maintain mutable state. They are purely structural.
    • Implementation: While a textual syntax for this language has been discussed for convenience, the current implementation requires you to directly build the object structure (the AST) using the available Dart classes.
  12. Understand reflection coverage and privacy limitations

    master

    Reflection in reflectable is designed to be space-efficient, which leads to certain intentional limitations:

    Privacy

    Because reflectable uses generated code to provide reflection, it cannot violate Dart's privacy rules. It cannot access private fields or methods declared in libraries different from the generated code.

    Incomplete Coverage

    Reflection support is not always a 'complete' view of an object. A class might be covered, but its methods might not be if they don't match the specified apiSelection (e.g., name regex or metadata requirements).