How to extend from const constructor - dart

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.

Related

What's the benefit of factory constructor in MapEntry class?

Original code for MapEntry
class MapEntry<K, V> {
final K key;
final V value;
const factory MapEntry(K key, V value) = MapEntry<K, V>._;
const MapEntry._(this.key, this.value);
}
What's the need to create above factory constructor when you can simply have:
class MapEntry<K, V> {
final K key;
final V value;
const MapEntry(this.key, this.value);
}
Writing the constructor like this effectively makes the class final (Classes are unable to extend from this class). Only generative constructors can be used to call super(). This is as opposed to factory constructors which cannot be used in such a way. As the only generative constructor is the private one named _, extension is prevented. There is the caveat that classes in the same package could extend the class as private members are available to classes in the same package.
By having the factory constructor, instances of MapEntry can still be created even though the default constructor is private.
class MapEntry<K, V> {
final K key;
final V value;
const factory MapEntry(K key, V value) = MapEntry<K, V>._;
const MapEntry._(this.key, this.value);
}
class ExtendableMapEntry<K, V> {
final K key;
final V value;
const ExtendableMapEntry(this.key, this.value);
}
// ---------------
class GoodChild extends ExtendableMapEntry<int, int>{
GoodChild(int i):super(i,i);
}
// Error:
// The constructor 'MapEntry<int, int> MapEntry(int key, int value)' is a
// factory constructor, but must be a generative constructor to be a valid
// superinitializer - line 24
class ImpossibleChild extends MapEntry<int, int>{
ImpossibleChild(int i):super(i,i);
}

Why there is a colon symbol (:) with the class constructor in Dart?

I am new in Dart(OOP Languange) which it is a bit similar in Java
But this code get me confusion
What is the purpose of colon(:) before the super keyword within SchoolID class that has been inherit with Person class?
Here is the code:
class Person {
String name;
int age;
int height;
Person({this.name, this.age, this.height});
}
class SchoolID extends Person {
int id;
int year;
String name;
SchoolID({this.id, this.year, this.name}) : super(name: name);
}
Another Example ,,, focus on colon the fishmap
AllFish.fromJson(Map<String, dynamic> json)
: fishMap = json.map(
(String k, dynamic v) => MapEntry(
k,
Fish.fromJson(v),
),
);
It's considered as an initializer list which runs before the constructor body, here you're calling the super that means the constructor of your Person class.
It's an initializer. This means the initializer is executed before the constructor body

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.

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.
}

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.

Resources