Dart: const variables must be initialized with a constant value - dart

Why there is an error, when the foo is already a const value?
const foo = const [10, 20];
const bar = foo[0] * 2; // error: const variables must be initialized with a constant value.

That's because while the variables used to create your second constant are constants, you also used the operator [] – which is not compile-time constant.
So while you can do:
const a = 42;
const b = a * 3;
you cannot do:
const array = [42];
const b = a[0];

Related

Dart: In constant expressions, operands of this operator must be of type 'num'

I created a const class like so:
class MyClass {
const MyClass(this.x, this.y);
final double x;
final double y;
MyClass operator +(MyClass other) {
return MyClass(x + other.x, y + other.y);
}
}
Now if I try to create a new class by adding two const values:
const objectA = MyClass(1, 4);
const objectB = MyClass(3, 2);
const objectC = objectA + objectB;
I get an error:
In constant expressions, operands of this operator must be of type 'num'.
If I use final it works, though:
final objectC = objectA + objectB;
I was going to say it's because the operator overload method creates a new class at runtime, but objectA and objectB were also created at runtime and they're constants. So why can't Dart allow objectC to be const?

How to assign a constant value as default value in constructor

class Foo {
final int x;
Foo([this.x = defValue]); // Compile-time error
static get defValue => 10;
}
Error:
The default value of an optional parameter must be a constant.
defValue is a compile time constant, so I should be able to pass its value to the constructor.
The expression defValue is not a compile-time constant expression. Evaluating it requires executing the getter to get a value, and constant evaluation cannot execute getters or methods (except a very specific list of allowed platform methods, like int.operator+). It might be that the expression returned by executing the defValue getter is itself a compile-time constant expression, but it's being returned through a non-constant operation.
Change the defValue definition to
static const defValue = 10;
then it should work. Reading constant declarations is a compile-time constant operation.
You refer to the docs saying that you can use a static method as a compile-time constant. That is correct, but that's the method itself which is the constant, you are still not allowed to call it.
That is:
static int foo(int x) => x;
static const fooRef = foo; // valid!
works because referencing the foo function value is a constant expression.
A getter is not a method, and you cannot do a "tear-off" of the getter. When you refer to it, you need to execute its body, and that's not allowed in a constant context.
My guess is that defValue is not known at compile time (since it's a getter and not a constant), so you should either use a constant variable like static const int defValue = 10 or initialize the class like this:
class Foo {
final int x;
Foo([int x]) : this.x = x ?? defValue;
static get defValue => 10;
}

What's the reasoning behind this colon in Dart

I'm checking out some dart code and looking at this:
AppState.fromJson(Map<String, dynamic> json)
: cartItems = (json['cartItems'] as List)
.map((i) => new CartItem.fromJson(i as Map<String, dynamic>))
.toList();
What's the reasoning behind the colon?
Why is this different from a regular assignment?
You can find more info in the dart tour: https://dart.dev/guides/language/language-tour#classes
If the superclass doesn’t have an unnamed, no-argument constructor, then you must manually call one of the constructors in the superclass. Specify the superclass constructor after a colon (:), just before the constructor body (if any).
Besides invoking a superclass constructor, you can also initialize instance variables before the constructor body runs. Separate initializers with commas.
// Initializer list sets instance variables before
// the constructor body runs.
Point.fromJson(Map<String, num> json)
: x = json['x'],
y = json['y'] {
print('In Point.fromJson(): ($x, $y)');
}
During development, you can validate inputs by using assert in the initializer list.
Point.withAssert(this.x, this.y) : assert(x >= 0) {
print('In Point.withAssert(): ($x, $y)');
}
You can also use them to initialize the final variables:
class Point {
final num x;
final num y;
final num distanceFromOrigin;
Point(x, y)
: x = x,
y = y,
distanceFromOrigin = sqrt(x * x + y * y);
}

How does Nix's "callPackage" call functions defined without an ellipsis?

To call a Nix function that uses set destructuring, you need to pass it a set with exactly the keys it requires, no more and no less:
nix-repl> ({ a }: a) { a = 4; b = 5; }
error: anonymous function at (string):1:2 called with unexpected argument ‘b’, at (string):1:1
The exception to this is if the function's argument list contains an ellipsis at the end:
nix-repl> ({ a, ... }: a) { a = 4; b = 5; }
4
However, most of the packages in nixpkgs consist of a default.nix file containing a function which is not defined with this ellipsis. Yet, somehow when you use callPackage, it manages to call these functions and pass them only the arguments that they need. How is this implemented?
There is a reflection primop, that can deconstruct function argument:
nix-repl> __functionArgs ( { x ? 1, y }: x )
{ x = true; y = false; }
callPackage then iterates over those attribute names, fetches required packages and constucts the attrset of packages, that is fed later to called function.
Here's a simple example:
nix-repl> callWithExtraArgs = f: args:
let
args' = __intersectAttrs (__functionArgs f) args;
in
f args'
nix-repl> callWithExtraArgs ({ x }: x + 1) { x = 4; y = 7; }
5
To browse Nix primops, go to 15.5. Built-in Functions in the Nix manual (or see the docs of the unstable branch).

meaning of const in `const ['foo', 'bar']` in dart

I know that const is compile-time constant in dart, but I don't understand mechanism behind const [F0, F1, F2] in the following code:
class Foo {
static const F0 = 'F0';
static const F1 = 'F1';
static const F2 = 'F2';
// const list of const values I guess...
static const CONST_LIST = const [F0, F1, F2]; // please explain this line
static final String FOO = CONST_LIST[0]; // ok
// compile error: 'const' varaibles must be constant value
// static const String BAR = CONST_LIST[1];
}
main() {
// is CONST_LIST const or not?
// below line it's ok for dartanalyzer but
// in runtime: Cannot change the content of an unmodifiable List
Foo.CONST_LIST[1] = 'new value';
}
I noticed that const is required by dart analyzer in const [F0, F1, F2]; but it does make list more like final (runtime immutable list) rather than compile time const.
UPDATE:
Another question is why CONST_LIST[1] is not "constant value". See commented declaration of Foo.BAR.
Günter has answered the second part of your question. Here is some more information about const.
Const means that the object's entire deep state can be determined entirely at compile time and that the object will be frozen and completely immutable.
More information in this article. Also see the following question.
Regarding the second part of your question, consider the following:
const int foo = 10 * 10;
The expression "10 * 10" can be evaluated at compile time, so it is a "constant expression". The types of things you can do in a constant expression need to be quite limited (otherwise you could run arbitrary Dart code in the compiler!). But some of these limitations are being relaxed as dart matures, as you can see in the bug which Günter linked to.
In contrast, consider the following:
final int bar = 10;
final int foo = bar * bar;
Since "bar * bar" is not a constant expression it is evaluated at runtime.
There is an open bug for this: see https://github.com/dart-lang/sdk/issues/3059

Resources