Difference between const constructor and cost? - dart

I have the following code snippet:
class ImmutablePoint {
final double x, y;
const ImmutablePoint(this.x, this.y);
}
void main() {
var i = const ImmutablePoint(4,6);
print(i.x);
}
As you can see, a const constructor is defined in the class. However, what is the difference between const and const constructor?
What is the difference when I change from var i = const ImmutablePoint(4,6); to var i = ImmutablePoint(4,6);?
The point is, sometimes I see in flutter example const Text("FFF"), although a const constructor is already defined for the text.

A class with a const constructor only allows you to create const instances of that class, but it does not make all instances const.
That is controlled at the constructor invocation site - the const constructor is only used within a const context. A const context is basically inferred by any precedingconst keyword, the following all would use the const constructor:
var foo = const ImmutablePoint(1,2);
const foo = ImmutablePoint(1,2);
var foos = const [ImmutablePoint(1,2)];
But the following would not, as it is not in a const context:
var foo = ImmutablePoint(1,2);

Related

Why can't you declare constant function literals in dart?

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
}

How to extend from const constructor

class and const gives a nice possibility to define structured constants. Now I try to extend from one, works ok. Try to use a constant from the inherited class, it works, still I only manage to get through with final instead of const. No big deal in my project, but is it possible to have it const?
class A {
final String name;
final int value;
const A(final String this.name, final this.value);
static const A ONE = const A('One', 1);
}
class B extends A {
const B(final String name, final int val) : super(name, val);
static const B B_ONE = const B('One', 1);//Ok
static const A A_ONE = A.ONE;//Ok
static final B BA_ONE = new B(A.ONE.name, A.ONE.value);//Ok
static const B BA_ONE_CONST = const B(A.ONE);//No B constructor!?!
}
Your B class indeed does not have a constructor that takes a single A instance. You haven't declared one, and you can't do it directly without a little workaround.
The problem is that B extends A, it doesn't just contain an A instance. So, if you want to start with an A instance (like A.ONE) and create a B instance from it, where B extends A and has its own name and value fields, you'll have to extract the name and value from the A to create the new object ... and you can't do property extraction in a const expression. So, that's a no-go.
What you can do is to have a different implementation of B that gets its values directly from an A instance, and then create a constant from that:
class B extends A {
const B(String name, int value) : super(name, value);
const factory B.fromA(A instance) = _SecretB;
...
static const B BA_ONE_CONST = const B.fromA(A.ONE);
}
class _SecretB implements B {
final A _instance;
const _SecretB(this._instance);
String get name => _instance.name;
int get value => _instance.value;
}
If you are the only one using the B.fromA constructor, you could just remove it and call the _SecretB constructor directly. If you want to expose it to other clients of your class, you can make it a const factory constructor like here.

how to get values from a const object?

I created a const object at app.config.dart with the following code:
const configObj = const {
'webServer': const {
'appBaseHref' : "/"
},
'auth0': const {
'apiKey': "foo",
'domain': "bar",
'callbackUrl': "callback"
}
};
now in my main dart file I import the app.config.dart and I try to get the values there and now idea how to do that. configObj.auth0.apiKey produces the error EXCEPTION: Class 'ImmutableMap' has no instance getter 'auth0'.
so how do I do this ?
thanks!
Dart doesn't support to access map entries with .
It should be:
configObj['auth0']['apiKey'];
Alternatively you can create classes for your configuration like
class WebServerConfig {
final String appBaseHref;
const WebServerConfig(this.appBaseHref);
}
class Auth0Config {
final String apiKey;
final String domain;
final String callbackUrl;
const Auth0(this.apiKey, this.domain, this.callbackUrl);
}
class MyConfig {
final WebServerConfig webServer;
final Auth0Config auth0;
const MyConfig(this.webServer, this.auth0);
}
const configObj = const MyConfig(
const WebServerConfig("/"),
const Auth0Config(
"foo",
"bar",
"callback"
)
);
This way you also get proper auto-completion when you access the config properties and can use the simple . notation to access properties.

print address of object

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.

How can I build an enum with Dart? [duplicate]

This question already has answers here:
Does Dart support enumerations?
(8 answers)
Closed 7 years ago.
The Dart language does not have enums (yet??). What is the proper or idiomatic way to construct an enum, at least until a language feature arrives?
Dart now has support for enums.
The rest of this answer is for Dart <= 1.8. If using > 1.8, use Dart's formal support for enums (explained in another answer).
It's true, the Dart language does not (yet?) have enums. There is an open issue for it.
In the meantime, here is an idiomatic Dart snippet to create your own enum.
class Enum {
final _value;
const Enum._internal(this._value);
toString() => 'Enum.$_value';
static const FOO = const Enum._internal('FOO');
static const BAR = const Enum._internal('BAR');
static const BAZ = const Enum._internal('BAZ');
}
Using const constructors means you can use this enum in a switch. Here's an example:
class Fruits {
final _value;
const Fruits._internal(this._value);
toString() => 'Enum.$_value';
static const APPLE = const Fruits._internal('APPLE');
static const PEAR = const Fruits._internal('PEAR');
static const BANANA = const Fruits._internal('BANANA');
}
void main() {
var yummy = Fruits.BANANA;
switch (yummy) {
case Fruits.APPLE:
print('an apple a day');
break;
case Fruits.PEAR:
print('genus Pyrus in the family Rosaceae');
break;
case Fruits.BANANA:
print('open from the bottom, it is easier');
break;
}
}
With r41815 Dart got native Enum support see http://dartbug.com/21416 and can be used like
enum Status {
none,
running,
stopped,
paused
}
void main() {
print(Status.values);
Status.values.forEach((v) => print('value: $v, index: ${v.index}'));
print('running: ${Status.running}, ${Status.running.index}');
print('running index: ${Status.values[1]}');
}
[Status.none, Status.running, Status.stopped, Status.paused]
value: Status.none, index: 0
value: Status.running, index: 1
value: Status.stopped, index: 2
value: Status.paused, index: 3
running: Status.running, 1
running index: Status.running
A limitation is that it is not possibly to set custom values for an enum item, they are automatically numbered.
More details at in this draft https://www.dartlang.org/docs/spec/EnumsTC52draft.pdf
I use a little bit simpler version of the Enum class in Dart Web Toolkit:
/**
* Emulation of Java Enum class.
*
* Example:
*
* class Meter<int> extends Enum<int> {
*
* const Meter(int val) : super (val);
*
* static const Meter HIGH = const Meter(100);
* static const Meter MIDDLE = const Meter(50);
* static const Meter LOW = const Meter(10);
* }
*
* and usage:
*
* assert (Meter.HIGH, 100);
* assert (Meter.HIGH is Meter);
*/
abstract class Enum<T> {
final T _value;
const Enum(this._value);
T get value => _value;
}
I like top-level constants for my enums. You can use imports to fix any collisions. This makes using the enums much less verbose.
i.e.
if (m == high) {}
instead of:
if (m == Meter.high) {}
Enum definition:
class Meter<int> extends Enum<int> {
const Meter(int val) : super (val);
}
const Meter high = const Meter(100);
const Meter middle = const Meter(50);
const Meter low = const Meter(10);

Resources