I saw a tutorial where he declared a function like this:
class Person {
String name;
Function(String name) doingHobby;
}
What does it mean? how is it differ with common Function with bracket?
This also not even looks like arrow function.
Thanks.
It means that doingHobby is a variable which is allowed to point to as function which returns dynamic (if we don't specify any return value, Dart will assume dynamic which basically means it is allowed to return anything including void) and takes one String argument.
Here is an example where I assign a void Function(String) to it using a constructor and later calls this function by using the doingHobby variable:
class Person {
String name;
void Function(String name) doingHobby;
Person(this.name, this.doingHobby);
}
void main() {
final person = Person(
'Jakob',
(hobby) => print('Doing $hobby'),
);
person.doingHobby('playing football'); // Doing playing football
}
Related
I'm trying to port some Dart code to another language but I'm a little confused by the .new constructor.
Given this class:
class DynamicTreeNode {
final int id;
DynamicTreeNode(this.id);
}
and this simple main function:
void main(List<String> arguments) {
List<DynamicTreeNode> _nodes = List<DynamicTreeNode>.generate(
16,
DynamicTreeNode.new,
);
}
I can see in the debugger that each instance of DynamicTreeNode is given an incrementing id value matching the index in the List:
Can someone explain what is happening here? I thought the call to new would fail as the unnamed (and only constructor) requires an int to be passed to it.
If we look at the List.generate constructor we can see that the signature is
List<E>.generate(
int length,
E generator(
int index
),
{bool growable = true}
)
The generator parameter — in your case DynamicTreeNode.new — is a function that takes the position in the list it is generated into as an argument and returns the type of element of the list. So the first DynamicTreeNode in the list will be generated by DynamicTreeNode.new(0), the second one as DynamicTreeNode.new(1), etc.
I'm not familiar with dart at all, but it looks like you're passing the .new function itself, and the .generate function on List<T> will construct an object under the hood by calling the .new function with an incrementing integer.
In JavaScript, that would look like this:
class DynamicTreeNode {
constructor(id) {
this.id = id;
}
}
const generate = (len, constructor) => new Array(len).fill(0).map((_, idx) => new constructor(idx));
function main() {
const _nodes = generate(16, DynamicTreeNode);
console.log(_nodes);
}
main();
I want to invoke functions of a class by their names inside a string. I know my best option are Mirrors.
var ref = reflect(new TestClass());
ref.invoke(Symbol("test"), []);
It works fine, I can call the function test by a string. But I also want to put "TestClass" inside a string. Is it possible somehow ?
var ref = reflect("TestClass");
ref.invoke(Symbol("test"), []);
Jonas
You can do something like this:
import 'dart:mirrors';
class MyClass {
static void myMethod() {
print('Hello World');
}
}
void main() {
callStaticMethodOnClass('MyClass', 'myMethod'); // Hello World
}
void callStaticMethodOnClass(String className, String methodName) {
final classSymbol = Symbol(className);
final methodSymbol = Symbol(methodName);
(currentMirrorSystem().isolate.rootLibrary.declarations[classSymbol]
as ClassMirror)
.invoke(methodSymbol, <dynamic>[]);
}
Note, that this implementation does require that myMethod is static since we are never creating any object but only operate directly on the class itself. You can create new objects from the class by calling newInstance on the ClassMirror but you will then need to call the constructor.
But I hope this is enough. If not, please ask and I can try add some more examples.
I am writing a native plugin that, in some cases, has to call functions in the Flutter portion of the app, written in Dart.
How it's achieved, is explained here:
https://flutter.io/platform-channels/
Furthermore, an example of invoking a method from the native/platform part towards the Dart/non-native is here:
https://github.com/flutter/plugins/tree/master/packages/quick_actions
Now, this example is really nice in case the platform only needs to invoke a method, i.e. that call returns nothing/void, but in case it needs to invoke a function, i.e. needs a return value from the non-native/Dart part, I could not have found an example or documentation on the internet. I believe it can be implemented though, because in the native Java part, there is a method:
public void invokeMethod(String method, Object arguments, MethodChannel.Result callback)
So, there is a callback object that could have a return value from the non-native part - or, I am mistaken here, and there is currently no way of returning a value from the non-native Dart portion of the app?
The signature is void setMethodCallHandler(Future<dynamic> handler(MethodCall call)), so we need to provide a function at the Dart end that returns Future<dynamic>, for example _channel.setMethodCallHandler(myUtilsHandler);
Then implement the handler. This one handles two methods foo and bar returning respectively String and double.
Future<dynamic> myUtilsHandler(MethodCall methodCall) async {
switch (methodCall.method) {
case 'foo':
return 'some string';
case 'bar':
return 123.0;
default:
throw MissingPluginException('notImplemented');
}
}
At the Java end the return value is passed to the success method of the Result callback.
channel.invokeMethod("foo", arguments, new Result() {
#Override
public void success(Object o) {
// this will be called with o = "some string"
}
#Override
public void error(String s, String s1, Object o) {}
#Override
public void notImplemented() {}
});
In Swift, the return value is an Any? passed to the result closure. (Not implemented is signaled by the any parameter being the const NSObject value FlutterMethodNotImplemented.)
channel.invokeMethod("foo", arguments: args, result: {(r:Any?) -> () in
// this will be called with r = "some string" (or FlutterMethodNotImplemented)
})
I have a List<String> of Dart function names. For example, ['func1', 'func2', 'func3']. I want to call each function in the List. How can I go from a String to a Function? The following code does not work, but conceptually it does what I want:
var func1 = Function('func1');
See how it creates a Function from 'func1'.
Edit: I need to deal with Strings because I read the list of functions from a file.
I don't think Dart allows that at the moment (for objects you could use dart:mirrors, but it's currently marked as an unstable library).
An alternative is to use a Map to associate the strings with the functions, as in:
void foo() {
print('foo');
}
void bar() {
print('bar');
}
void main() {
var functions = {
'foo': foo,
'bar': bar
};
// calling foo()
functions['foo']();
// or
var b = functions['bar'];
b();
}
There is nameof operator in C#, it allows to get property name at compile time:
var name = nameof(User.email);
Console.WriteLine(name);
//Prints: email
It is not possible to use reflection in flutter and I do not want to hardcode names of properties i.e. to be used for querying SQLite tables. Is there any workaround?
***Currently I'm using built_value library.
For the archives, I guess, this isn't possible as Dart doesn't store the names of variables after compiling, and as you mentioned, Flutter doesn't support reflection.
But you can still hardcode responsibly by grouping your properties as part of the object that they belong to, like with JSON:
class User {
final String email;
final String name;
const User({required this.email, required this.name});
Map toJson() => {
"email": email,
"name": name,
};
}
Instead of remembering to type out "email" and "name" whenever you use User, just call User.toJson(). Then, when you want to rename your variables, you can use your IDE's "rename all", or just skim over your User class to quickly change all of the names without missing any.
I'm currently monitoring the progress on the dart:mirrors package, which offers some neat reflective properties and methods, though, I hadn't found a simple way to just get the name of a symbol like nameof() does.
Example:
import 'dart:mirrors';
class User {
final String email;
final String name;
const User({required this.email, required this.name});
}
void main() {
reflectClass(User).declarations.forEach((key, value) {
print(value.simpleName);
});
}
Output:
Symbol("email")
Symbol("name")
Symbol("User")
These are of type Symbol.
More here: https://api.dart.dev/stable/2.4.0/dart-mirrors/dart-mirrors-library.html
So, until they develop a nameof, I've created an extension on symbol:
extension SymbolExtensions on Symbol {
String get nameof =>
RegExp(r'"(.*?)"').firstMatch(toString())!.group(1).toString();
}
So, you could do:
print(reflectClass(User)
.declarations[#email)]!
.simpleName
.nameof);
Output:
email
It's a start. Dart is still growing.
You can use code generation.
The basic idea is to create a nameof annotation class and mark parts of your code with it. You also need to create a code generator that handles your annotated code. Look at the json_serializable package for an example and create your own code generator.
If you do not want to create your own generator, use a ready-made package nameof: https://pub.dev/packages/nameof
Short how-to with this package.
Mark your class with nameof annotation.
#nameof
class Car {
final double price;
final double weigth;
final int year;
final String model;
Car(this.price, this.weigth, this.year, this.model);
Car.sedan(double price, double weigth, int year)
: this(price, weigth, year, 'Sedan');
}
Run the code generator.
flutter pub run build_runner build
Then use the generated class, which will look something like this.
/// Container for names of elements belonging to the [Car] class
abstract class NameofCar {
static const String className = 'Car';
static const String constructor = '';
static const String constructorSedan = 'sedan';
static const String fieldPrice = 'price';
static const String fieldWeigth = 'weigth';
static const String fieldYear = 'year';
static const String fieldModel = 'model';
}
You can implement your own nameOf function:
String? nameOf(dynamic o) {
if (o == null) return "null";
try {
if (o is List) {
var first = o.length > 0 ? o[0] : null;
if (first != null) {
var elementType = nameOf(first)!;
Log.debug("nameOf: List<$elementType>");
if (!isMinified(elementType))
return "List<$elementType>";
}
} else {
Function? getTypeName = o.getTypeName;
if (getTypeName != null) return getTypeName();
}
} catch (e) {
Log.debug("ignored nameOf error: $e, falling back to o.runtimeType: ${o.runtimeType}");
}
return o.runtimeType.toString();
}
bool isMinified(String type) => type.startsWith("minified:");