Is there a difference between instantiating objects in these two ways?
void main() {
var example = new ClassName()
}
vs
void main() {
var example = ClassName()
}
Since Dart 2.0 new is optional, so they are equivalent.
If the context requires const and new or const are omitted, then const is used automatically instead of new
(except for parameter default values because there the requirement for const might be dropped eventually)
Related
The question came into my mind when I've declared a final callback in a class, and the constructor can be declared as const, and trying to make a constant value of a function like so:
class MyClass {
final void Function() callback;
const MyClass(this.callback);
}
void example1() {
const foo = MyClass(() {});
}
This gives the error:
Why can I delcare a constant constructor in the first place? What would make an object of MyClass compile-time constant if no function value can be constant?
A simpler example:
typedef MyVoidCallback = void Function();
void example2() {
const MyVoidCallback bar = () {};
}
This gives the error:
Thank you in advance
It is because () {} is not a constant value, it is rather creating a new instance every time. All functions in dart inherit Function class which doesn't have const constructor.
However, since functions are top-level members in dart, you can pass them by name (like a variable). So if you define your function outside of any class such that it is a global function, you can pass it as a parameter value in a const constructor.
UPDATE from #randal-schwartz comment: Static functions inside a class can also be passed into these const constructors as parameters.
Below code should work:
class MyClass {
final void Function() callback;
const MyClass(this.callback);
}
void example1() {
const foo = MyClass(doWork);
}
void doWork() {
// TODO: do work
}
I have this code which works well on android emulator but gives error on web.
import 'package:parivaar/components/screens/home/Home.dart';
typedef T Constructor<T>();
final Map<String, Constructor<Object>> _constructors =
<String, Constructor<Object>>{};
void register<T>(Constructor<T> constructor) {
_constructors[T.toString()] = constructor;
}
class ClassBuilder {
static void registerClasses() {
register<Home>(() => Home());
}
static dynamic fromString(String type) {
return _constructors[type]();
}
}
And i am calling that function as follows:
class _MyHomePageState extends State {
KFDrawerController _drawerController;
#override
void initState() {
super.initState();
_drawerController = KFDrawerController(
initialPage: ClassBuilder.fromString('Home'),
.
..
...
....
You are probably assuming that T.toString() returns the source name of the type as a string. Nobody ever promised that.
It works on native, but on the web you often optimize for size and "minification" turns all the long names into shorter names. With that, the name of the type Home is no longer the string "Home".
I generally do not recommend depending on the string representation of types (or Type objects for that matter).
Consider changing register and fromString to:
void register<T>(Constructor<T> constructor) {
_constructors[T] = constructor;
}
and
static T fromType<T>() => _constructors[T]();
That relies on Type object equality, which is a well-defined operation.
Not perfect, but still better than going through strings.
If you need to create the objects dynamically from strings, where you don't know the type, then I'd instead require you to provide the key string on registration, changing register to:
void register<T>(String key, Constructor<T> constructor) {
_constructors[key] = constructor;
}
and register types like:
static void registerClasses() {
register<Home>("Home", () => Home());
}
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);
}
}
Is there any trick to print the address of a dart object?
I'm having an issue in which I have a standard enum class as described in Does Dart support enumerations?.
class Access {
static const IA = const Access._(0);
static const RO = const Access._(1);
static const RW = const Access._(2);
final int value;
const Access._(this.value);
...
}
The variable access is of type Access and the value is 1, yet access==Access.RO is returning false.
var access = _.access;
print('''
access => ($access, ${access.runtimeType}, ${access.value})
static => (${Access.RO}, ${Access.RO.runtimeType}, ${Access.RO.value})
equal ? => ${(access == Access.RO)}
''');
prints
access => (RO, Access, 1)
static => (RO, Access, 1)
equal ? => false
If I provide an operator==(Access other) that compares the values it returns the expected value. So, I figured maybe this has to do with coming at the class from different libraries (maybe isolate related) and if I could print the address of access and Access.RO I could see if they are different. Of course, if they were different I'd then need to know why as well.
When you deal with const you have to be very careful. If you use new Access._(0) instead of const Access._(0) you will not get the same object. Here is an example :
class Access {
static const IA = const Access._(0);
static const RO = const Access._(1);
static const RW = const Access._(2);
final int value;
const Access._(this.value);
}
main(){
print(Access.IA == const Access._(0)); // prints true
print(Access.IA == new Access._(0)); // prints false
}
This could explain your problem.
If identical(a, b) returns false you can be sure that their pointers are different. (The inverse is not necessarily true for numbers, but that's an implementation detail).
If you are dealing with isolates you need to be careful when you transmit objects. Even, if they are canonicalized on one side, they won't be, after they have been transmitted to another isolate:
import 'dart:async';
import 'dart:isolate';
class A { const A(); }
foo() {
port.receive((x, _) {
print(x == const A()); // Prints false.
});
}
main() {
var p = new ReceivePort(); // To keep the program running.
spawnFunction(foo).send(const A(), null);
}
Also note that dart2js doesn't allow to transmit arbitrary objects.
The behavior seems to be related to the presence of 'extends' as shown with unit test below:
typedef dynamic GetFromThing<T extends Thing>(T target);
typedef GetFromThing<T> DefGetFromThing<T extends Thing>(dynamic def);
typedef dynamic GetFromT<T>(T target);
typedef GetFromT<T> DefGetFromT<T>(dynamic def);
class Thing {
int value;
}
class Test {
static final GetFromThing<Thing> fromThingSimple = (Thing target) {
return target.value;
};
static final DefGetFromThing<Thing> fromThing = (dynamic def) {
return (target) => null;
};
static final DefGetFromT<int> fromInt = (dynamic def) {
return (target) => null;
};
}
main() {
test('this works', () {
var temp1 = Test.fromThingSimple(new Thing());
});
test('this works too', () {
var temp = Test.fromInt(10);
});
test('should let me call lexically closed functions', () {
var temp = Test.fromThing(10); // <-- causes test to hang
});
}
The fact that the VM hangs is clearly a bug. The code is legal. The fact that typedefs describe function types and can be generic whereas function types themselves are never generic is not an issue in principle (though it might be for the implementation).
I find it very interesting that type parameters in typedefs work without some kind of warning or error, since Dart doesn't have generic methods.
You very well may have come across two bugs here, the first that there's no errors, and the second that the VM hangs.