How retrieve function that marks with metadata - dart

Look at the following code snippet.
import "dart:mirrors";
class meta {
final String data;
const meta(this.data);
}
#meta("Tag")
doSomething() => print("You have to do something");
void main() {
doSomething();
}
How can I retrieve functions, that is market with metadata tags? In my example, I want to find out, which method is marked with meta tags.

you could do something like this:
void main() {
doSomething();
getMetaData();
}
void getMetaData() {
LibraryMirror currentLib = currentMirrorSystem().libraries.values.last;
currentLib.declarations.forEach((Symbol s, DeclarationMirror mirror) {
if(mirror.metadata.length > 0) {
print('Symbol $s has MetaData: "${mirror.metadata.first.reflectee.data}"');
}
});
}
This should give you:
You have to do something
Symbol Symbol("doSomething") has MetaData: "Tag"
You could also analyze your files from another project and use dart:mirrors on that file instead of inspecting the current library. Maybe libraries.values.last will not always return the current library - so you might need to change it. In my case it worked.

var decls = currentMirrorSystem().isolate.rootLibrary.declarations;
print(decls.keys.where((k) => decls[k] is MethodMirror &&
decls[k].metadata.where((k) => k.reflectee is meta).isNotEmpty));
see also How can i test the existence of a function in Dart?

Related

Dart type that is implemented by everything

I'm not quite sure how to phrase this but I basically want to write a function like this:
import 'dart:async';
int countBroadcastStreams(List<Stream<Object>> streams) {
return streams.where((s) => s.isBroadcast).length;
}
void main() {
final a = StreamController<int>.broadcast();
final b = StreamController<String>.broadcast();
countBroadcastStreams([
a.stream,
b.stream,
]);
}
This works, however if I change one of the StreamControllers to StreamController<Null> then it doesn't because Null is the only type that doesn't inherit Object.
So my question is: which type should I use instead of Object so it works with Null too? dynamic seems to work, but is that the best option? Does it introduce additional runtime cost?
I don't think the problem comes from the Object type. Try to explicitly specify that the Stream objects can be null:
import 'dart:async';
int countBroadcastStreams(List<Stream<Object?>> streams) {
return streams.where((s) => s != null && s.isBroadcast).length;
}
void main() {
final a = StreamController<int>.broadcast();
final b = StreamController<Null>.broadcast();
print(countBroadcastStreams([
a.stream,
b.stream,
]));
}
// console log: 2
Specify the nullable type for the stream objects: List<Stream<Object**?**>> streams.

Need help understanding => symbol in Dart

I came across the following Dart code while reading about first where. I wanted to understand what exactly is happening in this code as this is some syntax I am not familiar with, particularly the "=>" symbols.
void main() {
final list = List<Book>.generate(10, (id) => Book(id));
Book findBook(int id) => list.firstWhere((book) => book.id == id);
print(findBook(2).name);
print(findBook(4).name);
print(findBook(6).name);
}
class Book {
final int id;
String get name => "Book$id";
Book(this.id);
}
This is what is called Syntaxic sugar. It does not provide a special functionality but makes it easier for developer to write and read code.
In the cas of the => symbol, it is a shortcut for a function containing only a return statement. So those two definitions are exactly the same:
String main() {
return "Hello World"
}
String main() => "Hello World";
Note however, how the second one is way more readable.
So in your case if we unwrap everything your code would become:
void main() {
final list = List<Book>.generate(10, (id) {
return Book(id);
});
Book findBook(int id) {
return list.firstWhere((book) {
return book.id == id;
});
}
print(findBook(2).name);
print(findBook(4).name);
print(findBook(6).name);
}
class Book {
final int id;
String get name {
return "Book$id";
}
Book(this.id);
}

What's the equivalent to this[x] in Dart?

For instance, in Javascript I can do something like:
class Foo {
x = 'baz';
bar() {
const someVar = 'x';
console.log(this[someVar]);
// Output: 'baz';
}
}
Hopefully that's relatively clear - it boils down to accessing a member variable by another variable's contents. How is this achieved in Dart?
This is not trivial in Dart. Dart doesn't have a syntax to access class properties with [].
There are a couple of approaches though:
Mirrors:
https://api.dartlang.org/stable/2.6.1/dart-mirrors/dart-mirrors-library.html
Basically you have access to everything and offers the biggest freedom. You can check what properties a class has, access them via names and so on. Big disadvantage is that the generated JS (if targeting web) will be huge. Flutter doesn't support it at all.
Reflectable
To deal with the large generated JS, you can use package:reflectable. Never tried it with Flutter. It's a bit more to set up and start using bit it works.
Dart only solution 1
You can overload [] operator on a class:
class Foo {
final _backing = <String, String>{
'foo': 'bar'
};
operator [](String val) {
return _backing[val];
}
}
void main() {
final inst = Foo();
print(inst['foo']);
}
Dart only solution 2
Just use a map :) Well sort of... If you are dealing with complex types and you want to add some extra functionality to your map, you can do something like this:
import 'dart:collection';
class StringMap extends Object with MapMixin<String, String> {
final _backing = <String, String>{};
#override
String operator [](Object key) {
return _backing[key];
}
#override
void operator []=(String key, String value) {
_backing[key] = value;
}
#override
void clear() {
_backing.clear();
}
#override
Iterable<String> get keys => _backing.keys;
#override
String remove(Object key) {
return _backing.remove(key);
}
}

How return Future from Future? Or this is prohibited in async library?

How I can return Future value from Future object?
This code does not work.
import 'dart:async';
void main() {
var temp = foo();
temp.then((Future<int> future) {
future.then((int result) {
print(result);
});
});
}
Future<Future<int>> foo() {
return new Future<Future<int>>(() {
return new Future<int>(() => 5);
});
}
How to prevent unnecessary unwrapping?
In this case in async library 'Future' declared as generic class.
abstract class Future<T> {
}
If I create expression as the following
new Future<Future<int>>();
Then with type T specified as Future<int> which result expected from generic class Future?
I thing that result must be as specified in type argument T.
I.e. Future<int>.
But result is not as expected.
There is no information found about this abnormal behavior on Dart API site.
If this is a "feature" (but I think that abnormal behavior wrongly to call "feature') then why it not documented in Dart API?
How can be explained this discrepancy?
Why this code not generated errors and warnings?
Another IDENTICAL example but w/o using Future.
void main() {
var temp = foo();
temp.baz((Foo<int> foo) {
foo.baz((int result) {
print(result);
});
});
}
Foo<Foo<int>> foo() {
return new Foo<Foo<int>>(() {
return new Foo<int>(() => 5);
});
}
If in this case result will be as when using Future (i.e. unexpected) then how we can call this code?
Normal or abnormal?
Or maybe the Future in Dart some special (magic)?
Look at the api documentation
http://api.dartlang.org/docs/releases/latest/dart_async/Future.html
It says there:
If the returned value is itself a Future, completion of the created future will wait until
the returned future completes, and will then complete with the same result.
I guess that means you can't return a Future from a Future.
But you could return a list of futures.
void main() {
var temp = foo();
temp.then((List<Future<int>> list) {
list[0].then((int result) {
print(result);
});
});
}
Future<List<Future<int>>> foo() {
return new Future<List<Future<int>>>(() {
return [new Future<int>(() => 5)];
});
}
There is no need for any of that extra wrapping. According to the Future documentation:
If the returned value is itself a [Future], completion of the created
future will wait until the returned future completes, and will then
complete with the same result.
This means you can rewrite your code as:
import 'dart:async';
void main() {
var temp = foo();
temp.then((int result) {
print(result);
});
}
Future<int> foo() {
return new Future<int>(() {
return new Future<int>(() => 5);
});
}
This is a lot cleaner to work with and provides the expected result.

Creating function with variable number of arguments or parameters in Dart

I am looking for a way to create a function with a variable number of arguments or parameters in Dart. I know I could create an array parameter instead, but I would prefer to not do that because I'm working on a library where syntactic brevity is important.
For example, in plain JavaScript, we could do something like this (borrowed from here):
function superHeroes() {
for (var i = 0; i < arguments.length; i++) {
console.log("There's no stopping " + arguments[i]);
}
}
superHeroes('UberMan', 'Exceptional Woman', 'The Hunk');
However, in dart, that code will not run. Is there a way to do the same thing in dart? If not, is this something that is on the roadmap?
You can't do that for now.
I don't really know if varargs will come back - they were there some times ago but have been removed.
However it is possible to emulate varargs with Emulating functions. See the below code snippet.
typedef OnCall = dynamic Function(List arguments);
class VarargsFunction {
VarargsFunction(this._onCall);
final OnCall _onCall;
noSuchMethod(Invocation invocation) {
if (!invocation.isMethod || invocation.namedArguments.isNotEmpty)
super.noSuchMethod(invocation);
final arguments = invocation.positionalArguments;
return _onCall(arguments);
}
}
main() {
final superHeroes = VarargsFunction((arguments) {
for (final superHero in arguments) {
print("There's no stopping ${superHero}");
}
}) as dynamic;
superHeroes('UberMan', 'Exceptional Woman', 'The Hunk');
}
Dart does indirectly support var-args as long as you aren't too much into syntactic brevity.
void testFunction([List<dynamic> args=[]])
{
for(dynamic arg:args)
{
// Handle each arg...
}
}
testFunction([0, 1, 2, 3, 4, 5, 6]);
testFunction();
testFunction([0, 1, 2]);
Note: You can do the same thing with named parameters, but you'll have to handle things internally, just in case if the user (of that function; which could be you) decides to not pass any value to that named parameter.
I would like to thank #Ladicek for indirectly letting me know that a word like brevity exists in English.
This version:
Works with both positional and keyword arguments.
Supports typing of the return value.
Works with modern Dart.
typedef VarArgsCallback = void Function(List<dynamic> args, Map<String, dynamic> kwargs);
class VarArgsFunction {
final VarArgsCallback callback;
static var _offset = 'Symbol("'.length;
VarArgsFunction(this.callback);
void call() => callback([], {});
#override
dynamic noSuchMethod(Invocation inv) {
return callback(
inv.positionalArguments,
inv.namedArguments.map(
(_k, v) {
var k = _k.toString();
return MapEntry(k.substring(_offset, k.length - 2), v);
},
),
);
}
}
void main() {
dynamic myFunc = VarArgsFunction((args, kwargs) {
print('Got args: $args, kwargs: $kwargs');
});
myFunc(1, 2, x: true, y: false); // Got args: [1, 2], kwargs: {x: true, y: false}
}
Thanks, Alexandre for your answer!
I played around a little with Alexandre Ardhuin's answer and found that we can tweak a couple of things to make this work in the current version of Dart:
class VarArgsClass {
noSuchMethod(InvocationMirror invocation) {
if (invocation.memberName == 'superheroes') {
this.superheroes(invocation.positionalArguments);
}
}
void superheroes(List<String> heroNames) {
for (final superHero in heroNames) {
print("There's no stopping ${superHero}!");
}
}
}
main() {
new VarArgsClass().superheroes('UberMan', 'Exceptional Woman', 'The Hunk');
}
This has lots of problems, including:
A warning is generated wherever you call superheroes() because the signature doesn't match your parameters.
More manual checking would need to be done to make sure the list of arguments passed to superheroes is really a List<String>.
Needing to check the member name in noSuchMethod() makes it more likely you'll forget to change the 'superheroes' string if you change the method name.
Reflection makes the code path harder to trace.
BUT if you are fine with all of those issues, then this gets the job done.
If you are really into syntactic brevity, just declare a function/method with say 10 optional positional parameters and be done. It's unlikely someone will call that with more than 10 arguments.
If it sounds like a hack, that's because it is a hack. But I've seen the Dart team doing the same :-)
For example:
void someMethod(arg0, [arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9]) {
final args = [arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9];
args.removeWhere((value) => value == null);
/* do something the the args List */
print(args);
}
For the example you've written, I think you're best off using a list. Sorry about that!
I'm looking at dartbug.com, but I don't see a feature request for this. You're definitely welcome to create one!

Resources