What does the final modifier do in Dart? - dart

Dart has a concept of final. Most dynamic languages don't have this concept.
What is final and what do I use it for?

final variables can contain any value, but once assigned, a final variable can't be reassigned to any other value.
For example:
main() {
final msg = 'hello';
msg = 'not allowed'; // **ERROR**, program won't compile
}
final can also be used for instance variables in an object. A final field of a class must be set before the constructor body is run. A final field will not have an implicit setter created for it, because you can't set a new value on a final variable.
class Point {
final num x, y;
Point(this.x, this.y);
}
main() {
var p = new Point(1, 1);
print(p.x); // 1
p.x = 2; // WARNING, no such method
}
It's important to realize that final affects the variable, but not the object pointed to by the variable. That is, final doesn't make the variable's object immutable.
For example:
class Address {
String city;
String state;
Address(this.city, this.state);
}
main() {
final address = new Address("anytown", "hi");
address.city = 'waikiki';
print(address.city); // waikiki
}
In the above example, the address variable is marked as final, so it will always point to the object instantiated by the new Address("anytown", "hi") constructor. However, the object itself has state that is mutable, so it's perfectly valid to change the city. The only thing prevented by final is reassigning the address variable.

Related

How to set a default value for an optional positional parameter of type Function?

I am passing a Function as an optional parameter to the constructor but I can't assign a default value.
void main() {
Person p = Person();
print(p.foo('Hello'));
}
class Person {
final String Function(String) foo;
Person({this.foo});
}
now trying to assign a default value: Person({this.foo = (val) {return val;});
produces the error: Error: Not a constant expression. I am aware the parameter must be const but using const or even static infront of (val) {return val;} does not work.
Does anyone have an idea how to solve this problem?
You can try this:
void main() {
Person pLower = Person(foo: (a) => a.toLowerCase());
print(pLower.foo('Hello'));
Person pDefault = Person();
print(pDefault.foo('Hello'));
}
class Person {
static String defaultFoo(String a) => a.toUpperCase();
final String Function(String) foo;
Person({this.foo = defaultFoo});
}
Output
hello
HELLO
You can only use constant values (aka. compile-time constants) as default values.
You cannot create a constant function literal, so there is no way to write the function in-line in the constructor.
However, references to top-level or static functions are constants, so you can declare the default value function as a static function or top-level function.
void main() {
Person p = Person();
print(p.foo('Hello')); // Prints "Hello"
}
class Person {
final String Function(String) foo;
Person({this.foo = _identity});
static String _identity(String value) => value;
}
// or as top-level.
// String _identity(String value) => value;
You can (and should) choose to make the function public if the default value is on an instance method, and you expect anyone to extend or implement your class. In that case, they need to declare the same default value.
Another option, which is often at least as useful, is to not use a default value, but replace a null before using the value:
class Person {
final String Function(String) foo;
Person({String Function(String) foo}) : foo = foo ?? _identity;
static String _identity(String value) => value;
}
or even using a non-constant value:
class Person {
final String Function(String) foo;
Person({String Function(String) foo}) : foo = (foo ?? (String x) => x);
}
For a constructor, it makes very little difference. If it was an instance method instead, using ?? to replace null avoids subclasses having to use the exact same function as default value.
Personally I recommend always using ?? instead of a default value. It's more flexible since it allows non-constant values. For non-function default values, you'll have to document the default behavior instead of just letting the dartDoc show {int x = 42}, but for functions, you'll have to document them anyway.

How to return a non static field from a static method in Dart

Code:
class Rates {
static double get value => _value; // error
// Only constructor should set this value
final double _value;
Rates(this._value);
}
void main() {
// This is how I want to use value
final value = Rates.value;
}
I have mentioned what I need in comments section of the code, please let me know if you need more info.
What you are asking for is impossible, and it doesn't even make sense.
An instance field, like _value, exists on each instance of the class.
A static method, like the value getter, does not have access to any instance.
It's like being asked for the first word of the book ... without saying which book.
Actually I want Rates to hold a single value, and that value should only be initialised in constructor, plus I also want to use that value directly like Rates.value.
I still don't fully understand what you're trying to do nor why you'd want such a design (why bother with a class and a constructor at all?), but:
class Rates {
static double get value => _value;
static double _value;
Rates(double value) {
// Allow _value to be set only once. Further attempts will be ignored.
_value ??= value;
}
}
void main() {
Rates(42.0);
final value = Rates.value;
}
As currently written, there isn't any point to having the Rates constructor. It'd be simpler and less unusual to have a setter to initialize the value:
class Rates {
static double get value => _value;
static set value(double value) => _value ??= value;
static double _value;
}
or just make it freestanding with no class:
double get rateValue => _rateValue;
set rateValue(double value) => _rateValue ??= value;
double _rateValue;

what's the difference between static, final and const members at compile time in Dart? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
Like the title suggests, what's the difference between static, final and const at compile time in Dart?
When are they computed and when are memory allocated for each type?
Can a heavy use of static variables lead to performance issues or OOM?
static is to declar class level members (methods, fields, getters/setters).
They are in the class' namespace. They can only be accessed from within the class (not subclasses) or with the class name as prefix.
class Foo {
static bar() => print('bar');
void baz() => bar(); // ok
}
class Qux extens Foo {
void quux() => bar(); // error. There is no `bar()` on the `Qux` instance
}
main() {
var foo = Foo();
foo.bar(); // error. There is no `bar` on the `Foo` instance.
Foo.bar(); // ok
}
const is for compile time constants. Dart allows a limited set of expressions to calculate compile time constants.
const instances are canonicalized. This means multiple const Text('foo') (with the same 'foo' parameter value) are canonicalized and only one single instance will be created no matter where and how often this code occurs in your app.
class Foo {
const Foo(this.value);
// if there is a const constructor then all fields need to be `final`
final String value;
}
void main() {
const bar1 = Foo('bar');
const bar2 = Foo('bar');
identical(bar1, bar2); // true
}
final just means it can only be assigned to at declaration time.
For instance fields this means in in field initializers, by constructor parameters that assign with this.foo, or in the constructor initializer list, but not anymore when the constructor body is executed.
void main() {
final foo = Foo('foo');
foo = Foo('bar'); // error: Final variables can only be initialized when they are introduced
}
class Foo {
final String bar = 'bar';
final String baz;
final String qux;
Foo(this.baz);
Foo.other(this.baz) : qux = 'qux' * 3;
Foo.invalid(String baz) {
// error: Final `baz` and `qux` are not initialized
this.baz = baz;
this.qux = 'qux' * 3;
}
}
A static variable does not require an instance of the class to use.
Example:
class Math {
static var double staticPi = 3.14;
double var pi = 3.14;
}
class ClassThatUsesMath {
print(Math.staticPi);
// Non-static variable must initialize class first:
Math math = Math();
print(math.pi);
}
A final variable's value cannot be changed after it is assigned a value.
Example:
class Math {
final var pi = 3.14;
pi = 3.1415; // Error!
}
A const variable is similar to a final one in that it is immutable (cannot be changed). However, const values must be able to be calculated at compile time. const values will also be reused instead of being recalculated.
Example:
class MathClass {
const var section = 4;
const var examTime = DateTime.now(); // Error! Cannot be determined at compile time.
}

Dart: How to efficiently initialize multiple final fields that depend on the same calculation?

I have a Dart class with multiple fields that have to be final, because the class extends another class marked with #immutable.
The values of these fields are supposed to be calculated when an instance of the class is created. In Dart, "final instance variables must be initialized before the constructor body starts" (from dartlang.org).
In that scope, you can only call static methods.
That works for me except some fields depend on the same calculation, meaning that the same calculation is done twice.
Is there any way to avoid that, i.e. by saving some temporary result?
My current code:
class _IntegralCurve extends Curve {
static double delta = 0.01;
_IntegralCurve(this.original) :
integral = calculateIntegral(original),
values = calculateNormalizedValues(original);
final Curve original;
final double integral; // Accessible to other classes.
final Map<double, double> values;
/// Does the actual integrating work. Called twice.
static Map<double, double> integrate(Curve original) {
double integral = 0.0;
final values = Map<double, double>();
for (double t = 0.0; t <= 1.0; t += delta) {
integral += original.transform(t) * delta;
values[t] = integral;
}
values[1.0] = integral;
return values;
}
/// Calculates the integral.
static double calculateIntegral(Curve curve) => integrate(curve)[1];
/// Calculates cumulative values.
static Map<double, double> calculateNormalizedValues(Curve curve) {
final values = integrate(curve);
for (final double t in values.keys) {
values[t] = values[t] / values[1];
}
return values;
}
double transform(double t) {
for (final key in values.keys)
if (key > t)
return values[key];
return values[1.0];
}
}
Calculate the values in a factory constructor:
class _IntegralCurve extends Curve {
static double delta = 0.01;
factory _IntegralCurve(Curve original) {
final integral = calculateIntegral(original),
final values = calculateNormalizedValues(original);
return _IntegralCourve._(original, integral, values);
}
_IntegralCurve._(this.original, this.integral, this.values);
You can use a factory to hide calculations within a constructor without loosing the final:
class Foo {
final int computed;
final int copy;
Foo._(this.computed, this.copy);
factory Foo() {
// calculate value
int value = 42;
return Foo._(value, value);
}
}
If you only want this extra value to be looked up by other classes you could use the get keyword to compute other fields. This value will be computed every time it gets called though.
// Declaration
class Foo {
const Foo(this.initialValue);
final double initialValue;
double get computedValue => initialValue + initialValue;
}
// Usage
main() {
final foo = Foo(20);
print("${foo.initialValue} ${foo.computedValue}"); // Would print `20 40`
}
https://dart.dev/guides/language/language-tour#getters-and-setters

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.

Resources