dart-lang / sdk

The Dart SDK, including the VM, dart2js, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
9.97k stars 1.54k forks source link

Request for feedback: Discontinuing support for dart:mirrors #44489

Open mit-mit opened 3 years ago

mit-mit commented 3 years ago

The Dart mirrors core library (dart:mirrors) is currently in a sub-optimal state:

We've investigated potentially making mirrors a stable, fully supported offering, however in its current form this has a few large challenges:

  1. Dart has powerful "tree shaking" for ensuring we can produce apps with small code sizes. This relies on the ability to detect unused code, which doesn't work if reflection can use any of it dynamically (it essentially makes all code implicitly used).

  2. The APIs supported by mirrors are significantly behind the current Dart language, for example they do not support extension methods or null safety.

We believe that one of the core uses of mirrors is to do various forms of code generation and meta-programming. Before we potentially fully discontinue mirrors, we'd like to better understand the desired use cases here so that we could have alternative solutions and migration path ready for current users before we make any changes to dart:mirrors. If you have any such use cases, please leave a comment.

daniel-v commented 3 years ago

To make sure the info gets to you, here is my response to dart-misc mailing list:

I might be reading too much into this but discontinuing dart:mirrors library has some serious consequences that were not mentioned in your mail. The most important is that we'd lose the ability to do runtime reflection at our server-side code. It is an HTTP server that uses mirrors for the most important bits of it. Transitioning away from it is a scary proposal for many reasons.

If anything I'd request to add mirrors to AOT snapshots too, instead of discontinuing, so that we'd get to deploy our code as a single binary with all the benefits and drawbacks it means. But... Let me address the concerns I have:

I'm sure you have a list of pros and cons for mirrors vs. code generation too. Having said that, I'm not against the idea completely if there are good enough reasons. I'd have to bite my lips hard if mirrors were removed today and would have to migrate to pacakge:build but luckily we still have some time.

There have been several precedents where such a change was preceded by preparing users, crafting new tools or giving some extra attention to alternatives. Most recent one is the NNBD tooling to this. I hope it is the case here as well, in which case feedback on why I'm nervous about moving to pacakge:build is warranted here. In my opinion, build and associated packages are in a bad spot right now.

My recent incursions to writing builders were ... trying because:

  1. after awhile, I gave up trying to find written documentation for the questions I had, I started digging around in the code - this shows that the there is too little information out there about how to write builders, how it works and how to configure them. Eg. I was surprised to see that build.yaml and build.config.yaml are merged together instead of being taken as an absolute configuration BUT with a huge caveat: builder declarations are ignored from build.config.yaml.
  2. the configuration space is very complex and the tools do not aid me rooting out configurations that make no sense. ( ref ) Figuring out what is OK and what is not can only be done through trial and error or by reading the implementation. This is a problem for every user of package:build, not just builder authors.
  3. Contributors of package:build stated it is intended for "superusers" ( ref ). Context to it is: I brought up that it is difficult to map how I see code as a developer to how analyzer sees the same code, then write a builder around that mapping. dart:mirrors make it fairly easy. I fear that I would be required to run around in language specifications to figure out what is what for a question which as simple as: What is the first method in this class with an annotation of Route('/')? Example of how complicated it can be just to resolve types here (used by Angular Compiler too).

I've had some steep learning curves over the years. package:build was one of them. The primary reason - which I consider the most important of all - is a conceptual one: Code generation is becoming more and more important piece of the language ecosystem. As such, as a user of the language, my expectation is that such an important piece is well-documented, somewhat fool proof and fairly easily approachable.

I hope that this is the kind of feedback you were looking for to help you make the right decisions.

mit-mit commented 3 years ago

To those downvoting, it would be great if you could also post a comment with what concerns you. As mentioned, we'd like to understand the use cases where you use mirrors today, so that we can investigate if there is an alternate way by which we can support those use cases without mirrors.

zmeggyesi commented 3 years ago

I work with @daniel-v and @gothamgasworks - I can second Daniel's input that removing runtime reflection would impact us quite negatively.

Our product actively uses runtime reflection in server-side Dart code, both in production and in development, and our preference would be to retain the ability to introspect code rather than rely on build-time code generation, both in the interest of development cycle times and ease of understanding of deployed code.

gothamgasworks commented 3 years ago

@daniel-v 's summary is pretty good, I agree with them.

Some things I want to emphasize:

  1. Quick iteration, because we don't need to wait for builds (we use kernel snapshots on the production server)
  2. No need to develop builder code for every use case that may arise (we encountered quite a couple)
  3. Builder code development is a drag, we have to constantly update the code compared to our mirrors code, which we only had to touch once (moving from Dart 1 to 2)
gothamgasworks commented 3 years ago

We use dart:mirrors in:

Of course we could work around it with builders, I would just like to be able to not work with the builder/analyzer API, which requires a serious amount of maintenance as opposed to the mirrors API.

isoos commented 3 years ago

The use cases I had in the past month:

My wish-list, which would probably make the lack of dart:mirrors bearable:

Summary: To replace dart:mirrors, the following tools need to be available:

scheglov commented 3 years ago

The Dart Analyzer team uses package:test_reflective_loader extensively for all our tests, and it is based on using mirrors. We found out early that vanilla package:test is not structured enough for complicated package:analyzer tests.

lexaknyazev commented 3 years ago

My use case of reflection is docs generation via iterating over class members and invoking them to get sample outputs. The code using dart:mirrors resides in a grinder task thus being completely unaffected by the lack of support by web and AOT runtimes.

jakemac53 commented 3 years ago

I have mentioned this elsewhere but worth mentioning here for posterity - build_runner uses dart:mirrors in order to discover all of the libraries that exist in a program. In our case that is the build script itself, and we use that to know if we need to invalidate the snapshot.

gmpassos commented 3 years ago

I think that a new framework for reflection should exists. For now we should kill dart:mirrors.

In the future, after NNBD, a new framework should exists with another name. One where you can mark classes that should have their full description after compilation (the main information needed for runtime reflection). The marked classes could be by annotation or passing a list of classes for the "refletor factory" that should be tracked, allowing any class to be tracked for reflection. With that approach,Dart tree shaking won't be affected, unless you really need a reflected class for your project.

nex3 commented 3 years ago

dart:mirrors is used by Grinder, which is the best (and only) task runner for Dart with an 84% popularity rating on pub.dev, and my the mustache package which is used by both Dartdoc and the 99%-popularity google_fonts package. Both of these are load-bearing ecosystem packages. Removing dart:mirrors without a clear plan for something similarly usable for these packages would cause a lot of downstream pain and chaos.

It's worth noting that @isoos's proposed solution would likely not be sufficient for Grinder, since it's infeasible to have a code generation step as part of a task runner workflow.

tvolkert commented 3 years ago

This (a) doesn't solve all the problems with dart:mirrors, and (b) would only cater to specific use cases, but leaving the idea here nonetheless... what if we were to still tree-shake as normal even in the presence of dart:mirrors, and rely on developers marking methods as @pragma("vm:entry-point")?

DavidLiedle commented 3 years ago

My use case is... well, hold on just a dang minute.

I don't think I should have to lay out my thinking process to express the fact that I value the presence of dart:mirrors in the language. This "what is your use case?" approach smells of management and budgeting issues; not of nurturing the Dart ecosystem with an optimistic eye on the 10-20 year future of the language.

The APIs supported by mirrors are significantly behind the current Dart language, for example they do not support extension methods or null safety.

So allocate the dev resources to get on that. "Significantly behind" is a prioritization issue.

This is plainly technical debt. Defenestrating a sub-section of your server-side users building ORMs (oops, there's my use case..) would be an easy way out, and clearly a cheaper path forward. But seriously, cheaper over better? Not very Googley, imho. Do the right thing. Strive for excellence (and make the one thing you're doing really well be creating a language that can be used everywhere, including places where reflection makes sense). Keep an eye on the goals (both short and long term). Be proactive (and bring dart:mirrors up to par). Go the extra mile... Well, you know all this. You're the ones that work there.

I've been one of the earliest, most enthusiastic, and staunchest allies of both Dart and Flutter, but the bloom is off the rose with several prioritization choices that make me just, well, nervous. I'm tired of building things in AngularDart, or Polymer.dart (oy..), and then getting downstream just enough to feel the aging, unfinished edges and have to admit to myself that it's not a viable path forward. I have had to abandon chunks of my work because of hitting these dead ends and faded photos of what was planned. It's turning my attention to other places, and mine has teh sad. It took this thread for me to even glance back at AngularDart and see that it received an update in October of this year. Yay! But.. I can't trust it; already tried that, and got left behind.

TL;DR: this decision will impact the trust of your user base regarding your team's intentions in general; trust that is already flying on one engine. If we smell even a whiff of "Flutter doesn't need it so it's getting de-funded", even the features you do nurture will be untrusted for any other use case, and weaken your entire value proposition. Many of us, even your biggest fans, will simply walk. Not a rage-quit, but a pragmatic step out of what would appear to be a populism-driven-dev world and into other environments that focus on remaining well-rounded. Over time. For everyone.

The End

zmeggyesi commented 3 years ago

@gmpassos

For now we should kill dart:mirrors.

Not without a replacement being widely available and adopted we shouldn't!

Evidently, mirrors and reflection as a whole is widely used, in load-bearing packages as @nex3 points out, not to mention in the major task runner of the ecosystem. Killing mirrors without a replacement at this point pretty much breaks the ecosystem; killing it with a replacement that's not (near-)universally adopted does the same.

If the team moves forward with deprecating and removing this, it should only be done after they provided a replacement framework/solution, and the majority of the ecosystem, or at least its core components, have transitioned to the new way of doing things.

zmeggyesi commented 3 years ago

The more I think about code generation versus reflection/introspection, the more convinced I am that codegen as a whole, regardless of language, is a very double-edged sword (and that's leaving aside the fact that most generated code is fugly, but the saying is usually that you don't need to read it anyway - whether that's true is another thing entirely).

Either you persist the generated code, in which case you get the benefit of short build times, but you trade storage for it (you're persisting essentially redundant code) and you risk the generated code drifting from the handwritten code it's supposed to work with; or you ignore it (as in .gitignore it) and always regenerate it at build-time, in which case you lose fast builds, unless the build system can do some very clever incremental build magic, and you now have a piece of your application that is ephemeral and you lose the ability to fully understand the application based on the code alone, in exchange for the generated code always cooperating with the handwritten surroundings correctly.

Either way I slice it, I don't really see upsides to code generation as opposed to runtime reflection/introspection.

mraleph commented 3 years ago

I think original post by @mit-mit was a bit unclear: we have no plans to deprecate and remove dart:mirrors before we fully understand its current uses and at the very least have an alternative solution and a migration path (if necessary) for the current users. I took a liberty to edit @mit-mit's post to highlight this.

For me an ideal outcome would be that we end up staffing an effort to build a solution that covers dart:mirrors use cases, has similar usability/performance characteristics (no need to fiddle with code generation), simple migration path and works in AOT scenarios.

Another possible outcome is that we just invest some effort in bringing dart:mirrors in alignment with Dart 2.12 features.

Figuring out where we go requires feedback from current users of the library, so thanks to everybody who has provided it.

zmeggyesi commented 3 years ago

we just invest some effort in bringing dart:mirrors in alignment with Dart 2.12 features

I would very much like that, yes.

mit-mit commented 3 years ago

Thanks for all the feedback so far! Let me elaborate a bit, and answer a few questions:

@mraleph wrote:

I think original post by @mit-mit was a bit unclear: we have no plans to deprecate and remove dart:mirrors before we fully understand its current uses and at the very least have an alternative solution and a migration path (if necessary) for the current users.

Agree, the goal of this feedback issue is for us to better understand a) what critical uses mirrors have today, and b) based on those use cases, if we could design an alternate mechanism that could satisfy those same uses, but potentially be better aligned with our compiler goals.

@daniel-v wrote:

There is no proposal as to what would replace it, we need more info what you had in mind.

Correct, we don't have such a proposal yet. As I wrote above, we're hoping to learn how mirrors are being used today, and from that we'll potentially design an alternate mechanism, which we could then share for feedback.

cedvdb commented 3 years ago
  1. Dart has powerful "tree shaking" for ensuring we can produce apps with small code sizes. This relies on the ability to detect unused code, which doesn't work if reflection can use any of it dynamically (it essentially makes all code implicitly used).

@mit-mit Why ? Are you implying that if reflection is used, code that has nothing to do with what it was used with can't be tree shaken ? If I use reflectClass(SomeClass) , my whole codebase can still be tree shaked, minus that specific class. Alternatively, you could still tree shake that class and the reflection happens on the tree shaked class (assuming properties are tree shaked).

jakemac53 commented 3 years ago

If I use reflectClass(SomeClass) , my whole codebase can still be tree shaked, minus that specific class.

Not with the current dart:mirrors. From a single ClassMirror you can reach not only that class, but all classes referenced by that class in its return types and parameter types, etc.

And actually, its worse than that because you can also use the owner getter to get a mirror of the entire library, which exposes effectively all the transitive imports of the library.

This is just a part of the problem with the current dart:mirrors implementation, the ability to get from one mirror instance to just about anywhere else in the program through imperative code that is difficult to track the usage of (especially in the presence of anything dynamic).

srawlins commented 3 years ago

To expand on what @scheglov mentioned about test_reflective_loader: it uses a small piece of mirrors, but there is not another (codegen-free) solution:

The system is fed test classes with defineReflectiveTests(MyTest), and class MyTest has a series of test cases, which are each a public method on the class. So we use reflectClass, ClassMirror.metadata, and then ClassMirror.instanceMembers to get all of the test cases. We pass each MethodMirror to package:test by fetching the method as a field, and then invoking it with InstanceMirror.invoke. The ability to annotate test methods with @solo or @failingTest is important for our use case, so being able to grab a class's members and examine annotations are the core parts of test_reflective_loader's uses.

rdnobrega commented 3 years ago

I use mirrors for ORM, JSON serialization, documentation.. Reflection is a really big thing and should be a core part of Dart. Also it should be able to use in dart AOT.

Build_runner is not an option. If mirror is "experimental" build_runner is still a "thought" on production level. Too complicated to use and too low level to have actual value for programmers not interested in how the analyzer works. I mean, "I just want to get the properties' names and types, not learn how the dart analyzer works!". Also, it lacks documentation and greatly increases compile time.

I don't know how complicated the relation tree shaking-reflection is, and woudl love to read more about it, but since reflection could potentially access parts of code that was shaken off, it could have a property entitled "isShaken", so that devs can expect a specific element to exist but was shaken off, and trying to access it would raise an exception. To avoid exceptions, another method for reflection could be implemented like "reflectSafe()" which doesn't reference any part of dead code at all.

I don't like the idea to annotate members to be able to reflect, because it seems a downgrade for the current lib, but it's better than abandon reflection altogether.

Jonas-Sander commented 3 years ago

Just as a thought: With the advances in the Dart ecosystem on the Flutter side I think it is save to say that Dart will also have more adoption on the server side.
A recent example is the Functions Framework for Dart which you can use to run code in Google Cloud Run, Google App Engine and Knative-based environments.
So there may be even more desire for something like dart:mirrors in the future.

rdnobrega commented 3 years ago

@mit-mit Is there any news about this topic?

mit-mit commented 3 years ago

Thanks for all the feedback so far, it's very helpful!

We're currently doing some very initial brainstorming and exploration of some potential features in the meta-programming space. We speculate that they might support the kinds of use cases we're seeing in this thread, but it's too soon to tell with any certainty yet. We're going to explore that a bit more, and then share. For now, we're not making any decisions about mirrors until we understand the space a bit better.

RaedDev commented 3 years ago

I want to add my voice to the rest of the voices, my use case is to load modules dynamically and use the functions they provide. While this use case and most other use cases could be covered by code generation it's a trade of between more complex build process, and a tree-shaken code.

As many people have said, marking classes that should support reflection is great way to solve many problems, and having a flag to enable reflection on the whole project when the value of mirrors outweigh the costs. Rather than forcing one way of doing things that might not suit every use case.

gmpassos commented 3 years ago

I think that the biggest problem with reflection is the collateral effect with the tree shaking.

To minimize the problem, I think that the Reflector (the class that will use reflection, that will use use a Class X by reflection), should be the one that defines the classes that will be reflected (accessed by reflection), and not the opposite.

I saw in the past some frameworks where the class that will be reflected is self marked (usually with an annotation in the class). Actually reflection should exists to access any class, in the project or in other packages! This is the main mistake of the reflection frameworks in Dart, the miss conception that a reflected class should be marked in the class sources code itself.

If the reflector is the one that defines, statically, the classes to reflect, the side effect in the tree shaking will exists only in the marked classes for reflection.

A well defined interaction of reflection and tree shaking is the most important base for the whole framework, but no one is discussing this.

jakemac53 commented 3 years ago

@gmpassos I very much agree with you :). I have even hand coded something to mimic a theoretical "const reflection" proposal in this package https://github.com/jakemac53/static_reflection (sorry for lack of readme etc there). You can see that it does indeed not hinder tree shaking in the same ways that dart:mirrors or reflectable do. It is also a bit more cumbersome to use but I think the tradeoffs are worth it.

However this issue is more about just gathering use cases than it is brainstorming solutions :). Primarily we want to understand if a feature such as const reflection objects (note this is far from a real proposal) would solve all of peoples use cases.

bobjackman commented 3 years ago

I use reflection quite frequently in my unit tests as a way to mock, stub, and/or spy on classes/properties/methods that may not be exposed by 3rd parties. Removal of mirrors would cause a significant portion of my unit tests to fail.

dupuchba commented 3 years ago

@mit-mit we tried to use mirrors for Clojuredart but it was not supporting our use cases. We are using the analyzer package now. It's too bad because mirrors is really simple/fun to use whereas the analyzer is way much more work but returns all informations we need

Silentdoer commented 3 years ago

mirrors can use for write some framework like java's drools, esper ..

rdnobrega commented 2 years ago

Hi! Since this topic has opened and my opinion here, i learned golang and became very fond of it. And yes, reflection is something that really facilitates our daily lives. I have even constructed a small CLI library using reflection to facilitate building new commands and parsing, I even used reflection in my REST api to tell which fields could be CRUD from the http requests. That's certanly code that I will reuse, because it enabled a lot of things to be done quick and easy, just declare it on the tag and it works! It's awesome.

In the end, I had to build a Flutter app to communicate with this REST API and it was a real shock. Having to write down a lot of stuff that should be possible with simple reflection... It just broke my heart. I love Flutter/Dart and all of it's concept, specially its strongly typed system, but having to build lots and lots of boilerplate... It's not cool.

In fact, it is the reason that loose typed languages rise in the first place: strongly typed languages tend to become more and more tightened and adpotion falls... I don't want to see that with Dart/Flutter. Dart adoption in stackoverflow's 2020 report is almost negligent. This is sad, because dart and flutter are great tools, and I strongly think the lack of reflection its a part of this.

So, I will say something that might not be universal, but it is for me: code generation sucks. Honestly, i don't like code generation, we usually can't personalize very well and to add features? Forget it. Code generation is NOT a replacement for a good reflection system. Also, it is not easy to do a code generation tool yourself, so the value of it falls even more. I mean, code generation for JSON de/serialization? Such a simple thing and yet it is not supported at all.

In my mind, a good alternative for reflection in dart would be:

  1. Symbols (the # variables) should be statically linted to classes/types. So, if i type #Person.id, the linter should know that I'm talking about the variable 'id' of 'Person'.
  2. Classes should be able to be reflected dynamically, have its fields read and write to.
  3. Classes should be able to be instantiated dynamically by reflection.
  4. Libraries are not really that important to runtime reflection, and could be ignored, or not implemented at all.

All of this already exists in some kind, but it is not enabled for real development in flutter. Why? Reflection should not be an untammable beast. I would like it very much to have some kind of reflection, even if it is the most basic of all, to be enabled in flutter, it would really boost dart/flutter adoption to the moon.

gmpassos commented 2 years ago

About API backends:

It's hard to not have frameworks that can automate many definitions and behaviors common to the subject. The lack of reflection is definitely an issue to create this kind of frameworks.

So, I did it:

https://pub.dev/packages/reflection_factory

https://pub.dev/packages/bones_api

Any feedback is welcome.

An oficial reflection framework with the features of reflection_factory will be very nice.

Regards

bradcypert commented 2 years ago

Thanks for opening this up for feedback! I know a lot of people have already stated their case here in favor of supporting Mirrors but I wanted to make sure I was accounted for, too! I've been using Dart on the server-side for a while and having support for reflection has been extremely helpful. I understand why we may not want that in Flutter or on the web, but looking at Dart as it's own entity, I think there's a case to be made for supporting reflection :)

I'd love to see more server-side Dart, but I think that removing mirrors would disincentivize server-side development in Dart further. Thanks again for asking for the community's opinion on this one. I really appreciate having a chance to voice my opinion!

denisano commented 2 years ago

We're currently doing some very initial brainstorming and exploration of some potential features in the meta-programming space. We speculate that they might support the kinds of use cases we're seeing in this thread, but it's too soon to tell with any certainty yet. We're going to explore that a bit more, and then share. For now, we're not making any decisions about mirrors until we understand the space a bit better.

@mit-mit, could you please provide any news on this topic?

mit-mit commented 2 years ago

Sorry, no news yet (we will share it when we have it)

bradcypert commented 2 years ago

@mit-mit Anything we can do to help? Mirrors is very near and dear to me and I'd love to help us get that (or similar alternative) into a good state so that others can enjoy it, too ! 😊

labaxter commented 2 years ago

I've been coding since learning Basic on a Dartmouth teletype in the late '60s (that makes over 50 years!) , and I've worked in many languages. I'm relatively new to dart, but find it a really nice language.

I just attempted to compile JsonSerializable code (a dart shelf server) to a native executable and ran into this issue.

For me, the use case is the code generation of json serializable classes. When classes are large, and have contained classes (my use case), and persist and restore themselves to/from json, this code generation was a great find (saving many hours of custom code). For me, it would be nice if somehow there were a switch for dart compile exe that ignores the import of json_annotation.dart , the json annotations of the class definitions, and accepts the part files as non-generated code. (it might only have to ignore the import). I would never want to compile executables until I was ready to move to production, at which point any generation would be done. Now, I know there are probably lots of other powerful use cases for reflection, so ideally fixing reflection be ideal. But, switch to dart compile enabling compilation to native code would solve at least this use case.

I plan to use these same classes in a Flutter application, and so believe this will prevent me from compiling native code for my UI as well. I've figured out how to defeat this (by copying the generated code into my class definitions, removing the json_annotation imports, the part statements. and json annotations), but that is time consuming significant effort, and error prone. If i have to resort to that, I'll probably end up writing a script to do it. Not time I want to spend.

jakemac53 commented 2 years ago

@labaxter This is a bit off topic but you should be able to use json_serializable on all platforms without doing any copying around of files or anything like that - if you are experiencing issues I would file them on the repo.

labaxter commented 2 years ago

@jakemac53 I can use it just fine. The problem I believe is that it prevents dart compile exe with an AOT error.

Here is the dart program that compiles just fine

import 'dart:io';
//import 'package:vault/common/password.dart';
void main() async {
  Directory d = Directory.current;
  print("CWD: ${d.path}");
//  Password pw = Password("password",false);
//  print( pw.password );
}

$ dart compile exe bin/cmd.dart
Info: Compiling with sound null safety
Generated: /home/lab/src/vault/bin/cmd.exe
$

When I un-comment the references to the json_serializable class (Password), it fails to compile:


$ ~/src/vault dart compile exe bin/cmd.dart
Info: Compiling with sound null safety
error: import of dart:mirrors is not supported in the current Dart runtime
Error: AOT compilation failed
Generating AOT snapshot failed!
$

I've opened an issue with json_serializable (https://github.com/google/json_serializable.dart/issues/1097), as you suggest, but I suspect that it requires dart:mirror. Which is what lead me to this thread in the first place.

labaxter commented 2 years ago

@jakemac53 I've closed the issue I raised with https://github.com/google/json_serializable.dart. I'm going to have to did deeper to find the reference to dart:mirror. It might have something to do with my code organization, or something else I imported. I might be back, depending on what I find.

labaxter commented 2 years ago

See, my final comment here: https://github.com/google/json_serializable.dart/issues/1097 (closed) Apparently if one has a twisted enough set of imports, dart:mirrors gets referenced. There should probably be some kind of warning about this.

cabbi commented 2 years ago

I'm pretty new to dart & flutter, and I was surprised to see how easy it is to develop mobile apps with it. Then I moved forward with my experience and I was really surprised to see how many packages needed code generation to achieve their goals. I think a good language should not have that big need of code generation. Finally here is my whish list of what I expect to natively do with a dart object/class::

osa1 commented 2 years ago

we'd like to better understand the desired use cases here so that we could have alternative solutions and migration path ready for current users before we make any changes to dart:mirrors. If you have any such use cases, please leave a comment.

dart:mirrors is used in protobuf.dart tests. protoc_compiler generates classes that are subclass of GeneratedMessage (which inherits from Object). When generating these classes we don't want to be overriding GeneratedMessage or Object methods and properties. To avoid that we maintain a list of GeneratedMessage and Object method and property names, and if a proto field name is in that list we add a suffix to the field name and generate a method/property with the suffix.

To make sure the list is up-to-date with changes to GeneratedMessage or Object we have a test that collects GeneratedMessage methods and properties and compares those against the reserved names list. Collecting the method and property names is implemented here using dart:mirrors.

Without dart:mirrors we would have to manually make sure (as we update GeneratedMessage class, and also with newer versions of Dart, e.g. 2.14 added 3 static methods to Object) that the list of reserved names is in sync with GeneratedMessage and Object methods and properties.


If you know another way of getting methods and properties of a class (and its superclasses), maybe in compile time, without using runtime reflection, please let me know :-)

lrhn commented 2 years ago

Another approach to getting a list of members would be a source mirror like system, or maybe just a way for the analyzer to dump the APIs of selected classes as, e.g., JSON. You could start by running the analyzer, or a tool build on the analyzer, to dump the list of names of members of the classes you care about, then compare it to your current list.

Dumping the public API of a library would actually be a great way to detect accidental (or deliberate) changes between versions of the library, but finer granularity would also make sense.

modulovalue commented 2 years ago

I use mirrors ( + dart:cli + Isolate.resolvePackageUri) for synchronously getting an absolute filepath to the current file. (xkcd)

// ignore: deprecated_member_use
import 'dart:cli';
import 'dart:io';
import 'dart:isolate';
import 'dart:mirrors';

void main() {
  print(self_file(_Type));
}

abstract class _Type {}

File self_file(
  final Type type,
) =>
    File(
      // ignore: deprecated_member_use
      waitFor(
        Isolate.resolvePackageUri(
          reflectType(type).location!.sourceUri,
        ),
      )!
          .path,
    );
JakeSays commented 2 years ago

I use dart:mirrors for a tool similar to pigeon to generate custom type serializers, etc.

bradcypert commented 2 years ago

This also feels pretty bad, in my opinion. Maybe this is a pub issue, but it sucks that I wont be able to get full pub points for my package simply because I'm using mirrors.

Screen Shot 2022-06-03 at 10 35 02 AM
jakemac53 commented 2 years ago

This also feels pretty bad, in my opinion. Maybe this is a pub issue, but it sucks that I wont be able to get full pub points for my package simply because I'm using mirrors.

cc @jonasfj @sigurdm this does feel not quite right? Mirrors does work today for server applications (and also can be used anywhere the Dart VM is available, which includes Linux, macOS, Windows). This seems to be only checking for flutter builds and excluding command line applications.

Maybe a duplicate of https://github.com/dart-lang/pub-dev/issues/6410.

I thought there was another issue filed about how it is generally not fair to ding packages which are only intended to support a single platform (like Dart native), but I can't find it.

mit-mit commented 2 years ago

pub.dev has no way of knowing if a package is consumed by a Flutter app or a "VM app". Thus since Flutter release builds are AOT, where mirrors are not feasible, we modelled the scoring after that. I'm not sure how to resolve that without having a much more complicated UI on pub.dev where the developer would indicate what kind of app they are building...