Minimal reproducible code:
class Foo {
const Foo.one(Radius radius);
// Error: Evaluation of this constant expression throws an exception.
const Foo.two(double radius) : this.one(const Radius.circular(radius));
}
In the Foo.two constructor, why can't I just pass radius which itself is a constant? What's wrong in it?
PS: I don't want to fix the error by removing const from the constructor.
In the expression const Radius.circular(radius), the value of radius is not guaranteed to be const since initializing Foo as const is optional.
When you call a const constructor all of the arguments are required to be const as well, but it can't be guaranteed in this case.
Some people have requested that dart should support some kind of feature like this (github.com/dart-lang/language/issues/2000, github.com/dart-lang/language/issues/823), but it is not possible in dart currently.
An alternative would be to accept a Radius as an argument insted of double.
Related
I tried to run this code
var a = const [1, 2, 3];
a.add(10);
print(a);
but I am having an error. As I knew that assigning and const to a variable doesn't make it a const.
So why is this error occurring?
Unhandled exception: Unsupported operation: Cannot add to an
unmodifiable list
Variables in Dart is always references and the type of the variable does not change the state of the object it points to.
So in your case, you have declared a const list which means it is a compile-constant defined list and is therefore implicit unmodifiable.
You now point to this list by using a normal variable. But the type of the variable does not change the fact that your List is created as const from the beginning.
What is the difference between a and b below?
class ImmutablePoint {
const ImmutablePoint(this.x, this.y);
final int x;
final int y;
const ImmutablePoint.originA() : this(0, 0);
static const ImmutablePoint originB = const ImmutablePoint(0, 0);
}
void main() {
const a = ImmutablePoint.originA();
const b = ImmutablePoint.originB;
}
The constant variable defines and names a single value.
The const constructor defines a way to create new values.
If that constructor is invoked as const ImmutablePoint.originA() then, because of constant canonicalization, it creates the same constant value that the variable contains. However, you can also call new ImmutablePoint.originA() (with or without the new) and get a new instance which is not identical to any other point object.
A Dart constructor being const means that it can be invoked using const, not that it must.
From a literal perspective, one is a constructor and the other is a static variable. The constructor allows you to define constants, and the static variable already is a constant. That much should be fairly self-explanatory.
From a performance perspective? Both values resolve to the same constant-defined object:
const ImmutablePoint(0, 0);
Thanks to Dart's canonical constant feature, everything that references this constant class with the same values 0,0 (including other calls to ImmutablePoint.originA() or even ImmutablePoint(0, 0)) will be reduced to point to the same compile-time constant. So from a practical point of view, both the parameterless const constructor and the static const variable result in virtually identical compiled code and, therefore, performance.
(Though from a strictly nit-picky point of view, the static const might be compiled to include a static reference to the ImmutablePoint type before referencing the constant. I'm not knowledgeable enough with how Dart compiles these situations to say that for certainty, but I can tell you that even if it does happen, the performance hit for a static type reference will be in the "nanoseconds-or-less" tier of negligible. Don't micro-optimize, just use whatever approach you deem more readable or convenient.)
I was going through the Dart language tour and noticed that they have the statement
final constantSet = const {
'fluorine'
};
and I was just wondering whether there is a programmatic difference in declaring the constant as final or whether that has a specific purpose. I can see that we can place const either before or after the variable declaration, is this the same thing, considering that when you declare a variable as final it is only able to be initialized once anyway?
There is a difference.
A final constantSet = const {'fluorine'}; declares a non-constant final variable bound to a value which happens to be a compile-time constant.
A const constantSet = const {'fluorine'}; declares a constant variable bound to a compile-time constant value (and the second const can be omitted).
The latter allows you to use constantSet in constant expressions, so const [costantSet] is only valid with the latter declaration.
That also means that declaring a variable as const is something you cannot take back. Changing a const declaration to final may break code using the const variable in constant expression. That's a reason for not making every variable const, just because it can be. You might not want to promise that it stays constant forever.
Take this example:
void modl(List<int> l) {
l.add(90);
print(l);
}
class Foo {
final List<int> bar;
const Foo(this.bar);
#override
String toString() => 'Foo{bar: $bar}';
}
void main() {
var foo = const Foo([1,2,3,4]);
modl(foo.bar);
print (foo);
}
Running the above code results in a runtime Uncaught Error, but removing the const from
var foo = const Foo([1,2,3,4]);
allows it to work.
This seems like a bug to me because the const variable can be mutated and dart detects this at runtime, which means it has the means to detect when a const object is modified, but shouldn't this have been detected at compile time, seeing as const variables are called "compile-time constants".
If this is not a bug, is there anything in dart that allows us to detect at compile time when a const variable will possibly be mutated by an operation?
In C++, the compiler errors out when we try to do something like this. Is there anything we can do in Dart to avoid encountering this error at runtime?
No. Dart const is a compile-time feature around object creation, but it's not reflected in the type system.
You can't tell from the type of any object whether it's a constant or not.
Usually that's not a problem because an instance of a class which can be const is unmodifiable. It's not guaranteed to be deeply immutable, but the instance itself cannot have its fields changed.
Lists, sets and maps can both be either constant and mutable. That's what you are seeing here.
The list argument to const Foo(const [1, 2, 3, 4]) is constant, even if you remove the redundant const on the list literal. You would have the same issue with new Foo(const [1, 2, 3, 4]), which would also provide an immutable foo.bar, but which would otherwise be indistinguishable from new Foo([1, 2, 3, 4]). The only real difference is whether the list is modifiable or not, and the only way to detect that is to try to modify it.
Lists, sets and maps do not provide any way to detect whether they are mutable or not except trying, and catching the error.
When comparing to C++, Dart's notion of being const is a property of the object or, really, the way the object is created. That may have some consequences for the object. A const Foo(..) just creates a normal Foo object, but it can only create deeply immutable objects, and they are canonicalized. A const [...] or const {...} creates a different kind of list/map/set than the non-const literal, but that's not visible in the type.
In C++, being const is a property of an object reference, and it restricts how that reference can be used, but there are no constant objects as such. Any object can be passed as a const reference.
The two concepts are completely different in nature, and just happen to use the same name (and are also both different from JavaScript const).
const String IP_ADDRESS = "http://192.168.1.103:8088/";
const String HOME_EXPECTED = IP_ADDRESS + "index.html";
This code returns unexpected error message from Dart Editor.
An expression of type 'num' was expected
Why? and how can I fix it?
I tried using 'final', 'final const', and static. but failed :(
Update
http://dartbug.com/15853 says
So String+ String is a constant (and has been for a while). String* int isn't and is not expected to be.
I created http://dartbug.com/22408
Original
In Dart it is very limited how you can construct consts. The + operator on String isn't whitelisted for const creation.
Try this instead:
const String HOME_EXPECTED = "${IP_ADDRESS}index.html";
or
final String HOME_EXPECTED = IP_ADDRESS + "index.html";
if const is not required.
I don't know this language 'Dart' but looking at the language description, it is not possible to achieve what you want using 'const':
Use const for variables that you want to be compile-time constants. If the const variable is at the class level, mark it static const. (Instance variables can’t be const.) Where you declare the variable, set the value to a compile-time constant such as a literal, a const variable, or the result of an arithmetic operation on constant numbers.
Your second variable declaration is not a literal, a simple assignment to another const variable, nor is it an arithmetic operation of such.
Source: https://www.dartlang.org/docs/dart-up-and-running/ch02.html