Im currently experimenting with flutter, and I wrote the following code.
Text t1 = const Text("Hi");
Text t2 = const Text("Hi");
print(t1 == t2);
The print statement prints false, but because i'm creating two constants, shouldn't this print true?
For example if I were to create a class with the following code...
class Class1 {
final int? var1;
final int? var2;
const Class1(this.var1, this.var2);
}
Class1 ob1 = const Class1(1, 10);
Class1 ob2 = const Class1(1, 10);
print(ob1 == ob2);
This prints true for the objects being equal, how are widgets different from other objects in this regard?
Related
This question already has an answer here:
Is there a difference in how member variables are initialized in Dart?
(1 answer)
Closed 1 year ago.
I'm trying to understand the following example where I try to initialize a final variable in a constructor.
1st example - works
void main() {
Test example = new Test(1,2);
print(example.a); //print gives 1
}
class Test
{
final int a;
int b;
Test(this.a, this.b);
}
2nd example doesn't work
void main() {
Test example = new Test(1,2);
print(example.a); //compiler throws an error
}
class Test
{
final int a;
int b;
Test(int a, int b){
this.a = a;
this.b = b;
}
}
and when i remove final then it works again
void main() {
Test example = new Test(1,2);
print(example.a); //print gives 1
}
class Test
{
int a;
int b;
Test(int a, int b){
this.a = a;
this.b = b;
}
}
what is the difference between the constructor in the 1st and the 2nd constructor why final initialization works with the first and doesn't with the 2nd.
Can anyone explain that to me please?
THanks
You cannot instantiate final fields in the constructor body.
Instance variables can be final, in which case they must be set exactly once. Initialize final, non-late instance variables at declaration, using a constructor parameter, or using a constructor’s initializer list:
Declare a constructor by creating a function with the same name as
its class (plus, optionally, an additional identifier as described in
Named constructors). The most common form of constructor, the
generative constructor, creates a new instance of a class
syntax in the constructor (described in https://www.dartlang.org/guides/language/language-tour#constructors):
I want to store in a variable, the path to an element in a Map for quicker access later on
class Student{
String name;
int age;
Icon icon;
Color color;
Student(this.name, this.age, this.icon, this.color);
}
Student student_1 = Student('James', 14, Icon(Icons.label),Colors.green);
Student student_2 = Student('Andy', 12, Icon(Icons.label),Colors.blue);
Student student_3 = Student('Peter', 13, Icon(Icons.label),Colors.green);
Student student_4 = Student('Cathy', 15, Icon(Icons.label),Colors.pink);
Student student_5 = Student('Pamela', 14, Icon(Icons.label),Colors.amber);
Map<Student,dynamic> mapStudent = {student_1 : [student_2 , {student_3 : [student_4 , student_5,
student_2]}]};
var tmp = mapStudent[student_1][1][student_3][0];
The path I want to store is[student_1][1][student_3] so I can later access the details in that element without having to go through a loop. Is it possible?
I came across a Class called PathMap class but don't know how to use it or whether it is meant for what I'm trying to achieve.
PathMap class
I had a simmilar use case recently in which I had a List of items which belonged to a hierarchy for example:
factory Comment(
{required int id,
required String content,
required DateTime inserted,
CommentAuthor? commentAuthor,
int? parentId})/// This is the most important attribute `parentId`
Comments could be nested via its parentId just like Student in your map implementation.
I saw that hierarchy could be more correctly represented using trees so I created a slimmed down tree data structure like this one:
/// Simple N-ary tree data structure
class Node<T> {
final T value;
final List<Node<T>> children;
Node(this.value, {List<Node<T>>? children}) : children = children ?? [];
#override
bool operator ==(Object other) =>
identical(this, other) ||
other is Node &&
runtimeType == other.runtimeType &&
value == other.value &&
DeepCollectionEquality().equals(other.children, children);
#override
int get hashCode => value.hashCode ^ children.hashCode;
bool get isLeaf => children.isEmpty;
}
With this tree implementation now you have a safe, strongly typed hierarchy.
Extra : Transform list into tree (adapted from here)
/// Sample usage :
/// ```
/// List<Node<Comment>> commentListToTree(List<Comment> comments) {
/// return listToTree<Comment, int>(
/// comments,
/// idSelector: (c) => c.id,
/// parentIdSelector: (c) => c.parentId,
/// rootId: null,
/// );
/// }
/// ```
///
List<Node<T>> listToTree<T, IdType>(
List<T> list, {
required IdType? Function(T) idSelector,
required IdType? Function(T) parentIdSelector,
required IdType? rootId,
}) {
if (list.isEmpty) return [];
final tree = <Node<T>>[];
for (final item in list.where((e) => parentIdSelector(e) == rootId)) {
tree.add(Node<T>(
item,
children: listToTree(
list,
idSelector: idSelector,
parentIdSelector: parentIdSelector,
rootId: idSelector(item),
)));
}
return tree;
}
everybody, I just test the "const" and "new" keyword in Dart, and I found that:
If I want to create the exactly same instance, I must:
add the "const" keyword before the constructor declaration.
add the "const" keyword before any place I want to use the object.
like this:
class A {
final int x;
const A(this.x);
}
// when use
var a = const A(0);
var b = const A(0);
identical(a,b); // this is true, they are same instance
--------------------------- OK, so far, this is ok, but !!!! ----------------------------
When I also want to create two same "widgets", I failed!!
like this:
class A extends StatelessWidget {
final int x;
const A(this.x,{Key? key })
: super(key: key);
#override
Widget build(BuildContext context) {
return Container();
}
}
// when use
var a = const A(0);
var b = const A(0);
identical(a,b); // this is false!!!!!! why?????????
So.... Someone can tell me how to create two same instance widgets?? Thanks. :)
Welcome to SOF.
It's because Dart first instantiates an A then makes it constant, please don't confuse constant with static.
The reason the first sample gives identical=true is because both objects have similar hashCode.
(https://api.dart.dev/stable/2.10.5/dart-core/Object/hashCode.html)
hashCode is used for object comparison operations like ==
You should write this way, which is actually useless!:
var z = const A(0);
var a = z;
var b = z
identical(a,b);
Or you should override == and hashCode
I have a loop traversing a graph using a 'const' reference but when I assign my iteration variable I realize that it is non-const then I get nice compiler's complains.
class ClassDescriptor
{
const string name;
const TypeInfo type;
const ClassDescriptor base;
const IPropertyDescriptor[string] propertiesByName;
IPropertyDescriptor getFlattenProperty(string name)
{
// This declaration makes 'const(ClassDescriptor) bag'
// Note that in this point I can't add ref keyword.
auto bag = this;
while(!(bag is null))
{
if(name in bag.propertiesByName)
{
return bag.propertiesByName[name];
}
// This assigment breaks the constness
bag = bag.base;
}
return null;
}
public this(string name, TypeInfo type, ClassDescriptor base, const IPropertyDescriptor[string] propertiesByName)
{
this.name = name;
this.type = type;
this.base = base;
this.propertiesByName = propertiesByName;
}
}
Sounds like a job for std.typecons.Rebindable:
http://dpldocs.info/experimental-docs/std.typecons.Rebindable.html
import std.typecons;
Rebindable!(const typeof(this)) bag = this;
then the rest should work the same.
I have this fibonacci number generator.
struct FibonacciSeries
{
int first = 0;
int second = 1;
enum empty = false;
#property int front() const
{
return first;
}
void popFront()
{
int third = first + second;
first = second;
second = third;
}
#property FibonacciSeries save() const
{
return this;
}
}
This struct does not have the take method, so I have this error when executing this command (writeln(FibonacciSeries().take(5))).
a.d(66): Error: no property 'take' for type 'FibonacciSeries'
However, by importing range package, it has the take method. What's the mechanism behind this?
The mechanism is Uniform Function Call Syntax:
http://dlang.org/function.html#pseudo-member
To put it simply, if a.foo(b...) is not valid, the compiler tries rewriting it to foo(a, b...).