google / reflectable.dart

Reflectable is a Dart library that allows programmers to eliminate certain usages of dynamic reflection by specialization of reflective code to an equivalent implementation using only static techniques. The use of dynamic reflection is constrained in order to ensure that the specialized code can be generated and will have a reasonable size.
https://pub.dev/packages/reflectable
BSD 3-Clause "New" or "Revised" License
374 stars 56 forks source link

Unsupported operation: location #309

Open h3x4d3c1m4l opened 1 year ago

h3x4d3c1m4l commented 1 year ago

Hi! Very nice work on this library. Unfortunately it looks like it is not able to get the source code location of classes in the same library.

Example Reflector code:

class Reflector extends Reflectable {

  const Reflector() : super(typeCapability, typingCapability);

}

const reflector = Reflector();

@reflector
class Solver {
   ...
}

Code crashing with error Unsupported operation: location:

TypeMirror aMirror = reflector.reflectType(Solver);
var srcUri = aMirror.location.sourceUri;

As both Reflector and Solver class are in the same library, I would expect it to be able to get the source code location of the Solver class.

eernstg commented 1 year ago

Thanks for the kind words!

It is true that location was never implemented (nobody asked for it so far).

We could implement it (which would make the generated code somewhat bigger), or we could remove the location getter from the mirror types (to clearly indicate that it isn't supported).

Is there a good story about why the source code location of a declaration would be useful for a library / code generator that is intended to support reflection at run time?

sigurdm commented 1 year ago

We could implement it (which would make the generated code somewhat bigger), or we could remove the location getter from the mirror types (to clearly indicate that it isn't supported).

It would most likely still get tree-shaken away when not used - so maybe space is not a big concern here. (The problem is of course if there are dynamic invocation of a location getter somewhere...)

eernstg commented 1 year ago

That's an interesting trade-off!

We would presumably have a locationCapability, and it might be applied to some declarations and not to others (e.g., we might want to know the location of all classes that we have mirrors for, but not every one of their members).

This probably means that DeclarationMirrorImpl would have an instance variable, perhaps final SourceLocation? _location, and that instance variable would be non-null for every (declaration) mirror with a location.

That might not be a problem (one more instance variable per mirror might just be a few percent), but it is the kind of cost which is paid by everybody, rather than a 'pay as you go' cost.

If we have a suitable notion of equality we could also use a global Map<DeclarationMirrorImpl, SourceLocation>, which wouldn't make every single declaration mirror bigger.

h3x4d3c1m4l commented 1 year ago

Is there a good story about why the source code location of a declaration would be useful for a library / code generator that is intended to support reflection at run time?

So I have this personal project I would like to use for demo and experimental purposes (link). At the moment it just contains my Advent of Code solutions, for which I'd like every solver view to be able to show and link (to GitHub) it's source code. To achieve that:

It works well for now, but once I would move files, this could easily break. Being able to find the correct path in a dynamic way would be a very clean solution.