I have class with final variable (hash) and some other non-final variables.
Hash is unique value. And objects are stored in Set. Set uses '==' operand to check equality of objects. I want to override "==" and "hashCode" in my class and work with Set array.
To avoid using boilerplate code I want to use Equatable extension. Like this
class User extends Equatable {
final String hash;
String balance;
bool state;
....
#override
List<Object> get props => [hash];
} .... Set<User> users
Is it correct way to use Equatable in my case, 'cause it is uses with immutable classes.
Thanks!
Overriding hashCode to depend on non-final fields is usually not recommended because it can make Sets and Maps and other data structures that depend on hashCode internally inconsistent. Suppose you have such an object and insert it into a Set. Later, you mutate that object by assigning a new value to that field, but the Set would still have a reference to that object with the old hash code. For example, consider:
class Foo {
String s;
Foo(this.s);
#override
bool operator ==(Object other) {
return other is Foo && s == other.s;
}
#override
int get hashCode => s.hashCode;
#override
String toString() => s;
}
void main() {
var foo = Foo('foo');
var someSet = <Foo>{foo};
foo.s = 'bar';
print(someSet.contains(foo)); // Prints: false
someSet.add(foo);
print(someSet.length); // Prints: 2
print(someSet); // Prints: {bar, bar}
}
and now someSet would have two references to the exact same object, which violates its goal of storing unique objects.
A Map would have similar problems.
Since hashCode is tied to operator ==, this consequently also means that you usually shouldn't override operator == to depend on non-final fields.
You can get away with it if you can guarantee that you never mutate your objects while they're being referenced by a Set/Map/etc. or if you can guarantee that whenever you want to add your object to a Set/Map/etc. that you create a copy of your object and add that copy instead.
I'd say your use is correct.
You use Equatable only with the final field, so the equality and hash code should be stable over time, and the hash field is unique, so it can serve as identifier for the object.
If your hash field ends up not unique, you'll have two distinguishable objects that are equal, so ... don't do that.
Not sure how much you gain from using Equatable, though. If you wrote the equality and hash code yourself, it would just be:
bool operator==(Object other) => other is Foo && hash == other.hash;
int get hashCode => hash.hashCode;
class A {
final int? b; // Error
}
Error:
The final variable 'b' must be initialized.
Since the field b is nullable, it could be left uninitialised and hence needs no initialisation work. But it gives an error.
Not initializing a final field, regardless of whether it's nullable, is almost certainly a mistake. This was not different before null safety was introduced.
Suppose that final fields were allowed to be implicitly initialized to null. Then in a class such as:
class A {
final int? b;
}
there would be no point for b to exist at all since it'd always be null.
But maybe A provides a constructor that could initialize b to a non-null value:
class A {
final int? b;
A();
A.nonNull() : b = 42;
}
But now there's no way to tell if the default A() constructor actually wants b to be initialized to null or if the programmer just forgot to initialize it. The latter is much more likely, so Dart errs on the side of requiring explicit initialization.
You need to initialize b first like int b or string b; Assigning value is optional.
What is the difference between the const and final keywords in Dart?
There is a post on dart's website and it explains it pretty well.
Final:
"final" means single-assignment: a final variable or field must have an initializer. Once assigned a value, a final variable's value cannot be changed. final modifies variables.
Const:
"const" has a meaning that's a bit more complex and subtle in Dart. const modifies values. You can use it when creating collections, like const [1, 2, 3], and when constructing objects (instead of new) like const Point(2, 3). Here, 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.
Const objects have a couple of interesting properties and restrictions:
They must be created from data that can be calculated at compile time. A const object does not have access to anything you would need to calculate at runtime. 1 + 2 is a valid const expression, but new DateTime.now() is not.
They are deeply, transitively immutable. If you have a final field containing a collection, that collection can still be mutable. If you have a const collection, everything in it must also be const, recursively.
They are canonicalized. This is sort of like string interning: for any given const value, a single const object will be created and re-used no matter how many times the const expression(s) are evaluated.
So, what does this mean?
Const:
If the value you have is computed at runtime (new DateTime.now(), for example), you can not use a const for it. However, if the value is known at compile time (const a = 1;), then you should use const over final. There are 2 other large differences between const and final. Firstly, if you're using const inside a class, you have to declare it as static const rather than just const. Secondly, if you have a const collection, everything inside of that is in const. If you have a final collection, everything inside of that is not final.
Final:
final should be used over const if you don't know the value at compile time, and it will be calculated/grabbed at runtime. If you want an HTTP response that can't be changed, if you want to get something from a database, or if you want to read from a local file, use final. Anything that isn't known at compile time should be final over const.
With all of that being said, both const and final cannot be reassigned, but fields in a final object, as long as they aren't const or final themselves, can be reassigned (unlike const).
Const
Value must be known at compile-time, const birthday = "2008/12/25" Can't be changed after initialized.
Final
Value must be known at run-time, final birthday = getBirthDateFromDB() Can't be changed after initialized.
Consolidated #Meyi and #faisal-naseer answers and Comparing with little programming.
const:
const keyword used to make a variable to store a compile time constant value. Compile time constant value is a value which will be constant while compiling :-)
For example 5 is a compile time constant. While DateTime.now() which is not compile time constant. Because this method will return the time when the line is getting executed at runtime. So we can't assign the DateTime.now() to a const variable.
const a = 5;
// Uncommenting below statement will cause compile time error.
// Because we can't able to assign a runtime value to a const variable
// const b = DateTime.now();
Should be initialized at the same line.
const a = 5;
// Uncommenting below 2 statement will cause compilation error.
// Because const variable must be initialized at the same line.
// const b;
// b = 6;
All statements mentioned below are acceptable.
// Without type or var
const a = 5;
// With a type
const int b = 5;
// With var
const var c = 6;
Class level const variable should be initialized like below.
Class A {
static const a = 5;
}
Instance level const variable is not possible.
Class A {
// Uncommenting below statement will give compilation error.
// Because const is not possible to be used with instance level
// variable.
// const a = 5;
}
The another major use of const is used to make the object immutable. To make a class object immutable we need to use the const keyword with constructor and make all the fields as final like mentioned below.
Class A {
final a, b;
const A(this.a, this.b);
}
void main () {
// There is no way to change a field of object once it's
// initialized.
const immutableObja = const A(5, 6);
// Uncommenting below statement will give compilation error.
// Because you are trying to reinitialize a const variable
// with other value
// immutableObja = const A(7, 9);
// But the below one is not the same. Because we are mentioning objA
// is a variable of a class A. Not const. So we can able to assign
// another object of class A to objA.
A objA = const A(8, 9);
// Below statement is acceptable.
objA = const A(10, 11);
}
we can use const keyword to a list.
const a = const [] - A variable a initialized as const which contains a list of const objects(i.e., The list should contain only compile time constant and immutable objects). So we can't able to assign a with another list.
var a = const [] - A variable a initialized as var which contains a list const objects. So we can able to assign another list to the variable a.
Class A {
final a, b;
const A(this.a, this.b);
}
class B {
B(){ // Doing something }
}
void main() {
const constantListOfInt = const [5, 6, 7,
// Uncommenting below statement give compilation error.
// Because we are trying to add a runtime value
// to a constant list
// DateTime.now().millisecondsSinceEpoch
];
const constantListOfConstantObjA = const [
A(5, 6),
A(55, 88),
A(100, 9),
];
// Uncommenting below 2 statements will give compilation error.
// Because we are trying to reinitialize with a new list.
// constantListOfInt = [8, 9, 10];
// constantListOfConstantObjA = const[A(55, 77)];
// But the following lines are little different. Because we are just
// trying to assign a list of constant values to a variable. Which
// is acceptable
var variableWithConstantList = const [5, 6, 7];
variableWithConstantList = const [10, 11, 15];
var variableOfConstantListOfObjA = const [A(5, 8), A(7, 9), A(10, 4)];
variableWithConstantList = const [A(9, 10)];
}
final:
final keyword also used to make the variable to hold a constant value. Once initialized we can't change the value.
final a = 5;
// Uncommenting below statement will give compilation error.
// Because a is declared as final.
// a = 6;
All statements mentioned below are acceptable.
// Without type or var
final a = 5;
// With a type
final int b = 5;
// Can't use var along with final keyword. Uncommenting below line cause compilation issue.
// final var c = 6;
Able to assign a runtime value.
// DateTime.now() will return the time when the line is getting
// executed. Which is a runtime value.
final a = DateTime.now();
var b = 5;
final c = b;
Class level final variable must be initialized in the same line.
Class A {
static final a = 5;
static final b = DateTime.now();
}
Instance level final variable must be initialized in the same line or in the constructor initialization. The value will be put into memory when the object is created.
Class A {
final a = 5;
}
// Constructor with a parameter.
Class B {
final b;
B(this.b);
}
// Constructor with multiple parameter.
Class C {
final c;
C(this.c, int d) {
// Do something with d
}
}
void main() {
A objA = new A();
B objB = new B(5);
C objC = new C(5, 6);
}
Assigning a list.
final a = [5, 6, 7, 5.6, A()];
// Uncommenting Below statement will give compilation error.
// Because we are trying to reinitialize the object with another list.
// a = [9.9, 10, B()];
Extending the answer by #Meyi
final variable can only be set once and it is initialized when
accessed.(for example from code section below if you use the value of biggestNumberOndice only then the value will be initialized and memory will be assigned).
const is internally final in nature but the main difference is that
its compile time constant which is initialized during compilation
even if you don't use its value it will get initialized and will take
space in memory.
Variable from classes can be final but not constant and if you want a
constant at class level make it static const.
Code:
void main() {
// final demonstration
final biggestNumberOndice = '6';
// biggestNumberOndice = '8'; // Throws an error for reinitialization
// const
const smallestNumberOnDice = 1;
}
class TestClass {
final biggestNumberOndice = '6';
//const smallestNumberOnDice = 1; //Throws an error
//Error . only static fields can be declared as constants.
static const smallestNumberOnDice = 1;
}
const means its initial value is must be fixed, can not be a dynamic value;
final means its initial value is must be fixed but can be a dynamic value, equal to the var with a fixed value.
code demos
const
void main() {
const sum = 1 + 2;
// ✅ const can not change its value
print("sum = ${sum}");
// ⚠️ Const variables must be initialized with a constant value.
const time = new DateTime.now();
// ❌ Error: New expression is not a constant expression.
print("time = ${time}");
}
final
// new DateTime.now();
// dynamic timestamp
void main() {
final sum = 1 + 2;
// ✅ final can not change its value
print("sum = ${sum}");
final time = new DateTime.now();
// ✅ final === var with fixed value
print("time = ${time}");
}
Screenshots
refs
https://dart.dev/guides/language/language-tour#final-and-const
final and const in dart are confusing to the level we think both of them are the same.
Let's see their differences :
P.S. I included image instead of text as I couldn't tabulate the info
in Stackoverflow .md format easily.
Both final and const prevent a variable from being reassigned (similar to how final works in Java or how const works in JavaScript).
The difference has to do with how memory is allocated. Memory is allocated for a final variable at runtime, and for a const variable at compile-time. The final modifier should be the more commonly used, because many program variables won't need any memory since the program logic won't call for them to be initialized. With a const variable you are basically telling the computer, "Hey, I need memory for this variable up front because I know I'm going to need it."
Thinking of them in this way makes it easier to understand differences in their syntactical usage. Mainly that a final variable may be an instance variable, but a const must be a static variable on a class. This is because instance variables are created at runtime, and const variables--by definition--are not. Thus, const variables on a class must be static, which means simply that a single copy of that variable exists on a class, regardless of whether that class is instantiated.
This video breaks it down fairly simply:
https://www.youtube.com/watch?v=9ZZL3iyf4Vk
This article goes into more depth and explains a very important semantic difference between the two, i.e. final modifies variables and const modifies values, which essentially boils down to only being able to initialize const values which are derivable at compile-time.
https://news.dartlang.org/2012/06/const-static-final-oh-my.html
Anything that isn't known at compile time should be final over const.
If you are coming from C++ then const in Dart is constexpr in C++ and final in Dart is const in C++.
The above applies to primitive types only.
However in Dart objects marked final are mutable in terms of it's members.
Simple words:
Const
Value must be known at compile-time, i.e. values coming from internal files.
Sample: API keys, supported languages of your app or any variables in your i.e. helper file, basically anything which you ship with your app.
Final
Value must be known at run-time.
It can be data like above but also i.e. device info which will be checked when the app is starting or data that is loaded from API's or servers when the app starts, but before the app is ready to use i.e. you need to check if the user is logged in or not, your app would load or check a session token from the server.
The answer is in the image itself.
const is a Compile-time constant.
final is a Run-time constant.
All these answers I can describe in a concise way.
const list = [1, 2, 3];
Both variable/identifier & value are const. Like - const list = const [1, 2, 3]
That's why they are not allowed to be re-assigned.
Good fit for global variables.
It is possible to use it as a class variable but have to set static. Like - static const list = [1, 2, 3].
vs:
final list = [1, 2, 3];
Variable/Identifier is const but value is not. Like - const list = [1, 2, 3]
That's why we can perform like - list.add(4)
You can't initialise a const using a final. For example :
final myConst = 1;
const myFinal = 2;
final a = myConst; // possible
final b = myFinal; // possible
const c = myConst; // this is not possible
const d = myFinal; // possible
When to use which keyword?
A simple example for both:
Use final: If you don’t know what it’s value will be at compile-time. For example, when you can need to get data from an API, this happens when running your code.
Use const: If you are sure that a value isn’t going to be changed when running your code. For example, when you declare a sentence that always remains the same.
https://itnext.io/difference-between-const-and-final-in-dart-78c129d0c573
A variable with the final keyword will be initialized at runtime and can only be assigned for a single time.
A variable with the const keyword is initialized at compile-time and is already assigned when at runtime.
Use final: If you don’t know what it’s value will be at compile-time. For example, when you can need to get data from an API, this happens when running your code.
Use const: If you are sure that a value isn’t going to be changed when running your code. For example, when you declare a sentence that always remains the same.
I was trying out the new ref returns of C#7.
I am able to compile and build this:
public ref string MisUseRefReturn(int index)
{
string[] array = { "a", "b", "c", "d" };
return ref array[index]; //array[2] gets out of scope when this method returns!
}
According to MSDN: The return value cannot be a local variable in the method that returns it; it must have a scope that is outside the method that returns it. It can be an instance or static field of a class, or it can be an argument passed to the method. Attempting to return a local variable generates compiler error CS8168, "Cannot return local 'obj' by reference because it is not a ref local."
So why does this compile? When I execute this method, the returned reference shows the correct string.
Think of the array element as if it were an instance field of the array. Imagine your array were:
public class FourElementStringArray
{
public string element0;
public string element1;
public string element2;
public string element3;
}
Then your code is equivalent to:
public ref string MisUseRefReturn(int index)
{
var array = new FourElementStringArray
{
element0 = "a",
element1 = "b",
element2 = "c",
element3 = "d"
};
// TODO: do this dynamically based on index
return ref array.element2;
}
That abides by the piece of documentation you quoted:
It can be an instance or static field of a class, or it can be an argument passed to the method.
Is this useful? Not particularly. Is it dangerous? No.
The latter part is the important point. Using the regular array, if the caller assigns a new value, that's fine - it's replacing an element of an array, on the heap. The array can't be garbage collected while the array element reference exists; all is basically okay.
What the compiler rule is trying to prevent is the use of a returned reference to somewhere on the stack which has then been popped by the method returning. The array itself isn't on the stack, so there's no problem here.
See the description here:
Returning a local int variable instead of an array is not possible.
int is a value type, and thus the variable gets out of scope at the
end of the method, and thus a reference to it cannot be returned.
That’s different with an array. An array is a reference type, and the
array is allocated on the heap. An int within the array can be
returned with the ref keyword.
You could not return an integer value directly as it is a value type. An array element can be returned because it is a reference type. The MSDN statement is correct.
... of an array that only exists inside the method
The returned reference persists the array beyond the method call.
I want to fill Dictionary via a method of which dictionary is one of the parameter. When I add a value to key, say 15, it always return 0 count when I try to access it second time with same key i.e. 15. Here's the code.
private static var showWidgetMap = Dictionary<Int, [BaseWidget]>()
private static var hideWidgetMap = Dictionary<Int, [BaseWidget]>()
static func initHandler()
{
let cloudWidget = CloudWidget()
cloudWidget.setType(CreatorConstants.CLOUD)
let property1 = [CreatorConstants.IMG_SRC: "cloud1", CreatorConstants.X_COORD: "100", CreatorConstants.Y_COORD: "450"]
cloudWidget.setPropery(property1)
addWidgetInLocalTimeList(15, widget: cloudWidget, delete: false)
let emojiWidget = CloudWidget()
emojiWidget.setType(CreatorConstants.EMOTICON)
let property2 = [CreatorConstants.IMG_SRC: "1", CreatorConstants.X_COORD: "100", CreatorConstants.Y_COORD: "550"]
emojiWidget.setPropery(property2)
addWidgetInLocalTimeList(15, widget: emojiWidget, delete: false)}
static func addWidgetInLocalTimeList(time_milisec: Int, widget: BaseWidget, delete: Bool)
{
if(delete)
{
checkAndAdd(hideWidgetMap, key: time_milisec, widget: widget);
}
else
{
checkAndAdd(showWidgetMap, key: time_milisec, widget: widget);
}
}
private static func checkAndAdd(var map: Dictionary<Int, [BaseWidget]>, key: Int, widget: BaseWidget)
{
print("map count is")
print(map.count)
if var val = map[key]
{
val.append(widget);
}
else
{
var temp: [BaseWidget] = [];
temp.append(widget);
map[key] = temp
print(map.count)
}
}
print(map.count) always returns 0.
You need to understand the difference between value types and reference types.
Value type variables are just values. For example, an array is a value type. It is just a value of "a bunch of stuff" *. On the other hand, reference types are references to values. For example, when you create a UIViewController, that variable actually stores a reference to the actual UIviewController *.
Don't really understand? Then it's analogy time! The variables and constants you create are children. The things you put in variables and constants are balloons.
There are two types of children, one type (value types) likes to hold balloons directly in their hands. The other type (reference types) likes to hold balloons using a string **.
When you pass a child to a method, depending on what type of child he is, different things will happen:
A value type child holds the balloon in his hands, so tightly that the method parameter can't take it away from him. So what can it do? It creates a copy of it! It then takes the copy to the method implementation let it do its thing.
A reference type, however, holds balloons using a string. The method parameter will tie another string to the balloon so the implementation can access it using the string. As a result, no copies of the balloon are created.
So what are you doing wrong here?
Since swift dictionaries are value types, when you pass a dictionary to a method, as I said above, it creates a copy! In the implementation, you are actually editing a copy of the dictionary, not the original one. That's why the original dictionary still has a count of 0.
What can you do?
Instead of marking the parameter with var, which is a very bad practice btw, you mark it with inout!
private static func checkAndAdd(inout map: Dictionary<Int, [BaseWidget]>, key: Int, widget: BaseWidget)
The inout modifier basically says
Hey parameter, next time you see a value type, just get a string and tie it to the balloon that the child is holding.
There is also another thing that you should do. That is you should change the way you call your method.
Instead of
checkAndAdd(showWidgetMap, key: time_milisec, widget: widget)
You write
checkAndAdd(&showWidgetMap, key: time_milisec, widget: widget)
And magically, it works!
Conclusion: Parameters are dumb. They aren't even smart enough to know when to tie a string. Be careful when you work with value types.
Footnotes * Assume it is not nil
** Not the String type, but an actual string.