Difference between static and const variable in Dart - flutter

Check these two examples:
static const inside of class:
class SessionStorage {
static const String _keySessionExist = 'storage.key';
}
Just a const outside of the class:
const String _keySessionExist = 'storage.key';
class SessionStorage {
}
Is there any difference or implications between having a static const variable inside of a class or just having it declared as const outside of it in Dart?
Maybe the compiled code changes?
Which one is more performant?
Which one should we follow if the variable is private to the file?

The declaration for cons must be using const. You have to declare it as static const rather than just const.
static, final, and const mean entirely distinct things in Dart:
static means a member is available on the class itself instead of on instances of the class. That's all it means, and it isn't used for anything else. static modifies members.
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 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. In other words:
getConst() => const [1, 2];
main() {
var a = getConst();
var b = getConst();
print(a === b); // true
}
I think Dart does a pretty good job of keeping the semantics and the keywords nicely clear and distinct. (There was a time where const was used both for const and final. It was confusing.) The only downside is that when you want to indicate a member that is single-assignment and on the class itself, you have to use both keywords: static final.
Also:
I suggest you to have a look at this question
What is the difference between the "const" and "final" keywords in Dart?

Is there any difference or implications between having a static const variable inside of a class or just having it declared as const outside of it in Dart?
The obvious difference is that the static version must be referenced with the class name. Other than the change in name resolution, the should be the same.
Maybe the compiled code changes?
Which one is more performant?
They're both compile-time constants. There shouldn't be any difference.
Which one should we follow if the variable is private to the file?
If you want something that's private to a Dart library (which usually means the file), then prefix it with _. It doesn't matter whether it's global or static.

Related

Declaring list in dart with const and modifying it giving runtime error not a compile time

In dart, why
const cities = ['Delhi', 'UP', 'Noida'];
//error is in this line
cities[0] = 'Mumbai';
is a runtime error, not a compile time error?
See this answer for knowing the implications of const in dart
TLDR const variables are pre compile by dart and you cannot modify them at runtime.
const cities = ['Delhi', 'UP', 'Noida'];
cities[0] = 'Mumbai'; // Throws at runtime
Use final or var instead.
final cities = ['Delhi', 'UP', 'Noida'];
cities[0] = 'Mumbai'; // Works OK
https://www.peachpit.com/articles/article.aspx?p=2468332&seqNum=5#:~:text=EXAMPLE%204.12&text=Unlike%20final%20variables%2C%20properties%20of,its%20values%20cannot%20be%20changed.
Use normal variables, as with constants, you cannot change the value of the list during runtime.
I assume that is done with
var or final, as I'm not a dart master myself.
There currently is no way of indicating in Dart whether a method mutates its object or is guaranteed to leave it alone. (This is unlike, say, C++ where a method could be marked as const to indicate that it does not (visibly) mutate the object.)
Consequently, there isn't a good way for the Dart compiler to know that operator []= shouldn't be allowed to be invoked on a const object, so unfortunately it isn't known that it violates the const-ness of the object until runtime.

why does my indexOf output -1 in flutter?

class Task{
String name;
bool isDone;
Task({this.name, this.isDone = false});
}
class TaskData{
List<Task> tasks = [
Task(name: 'Buy milk'),
Task(name: 'Buy eggs'),
Task(name: 'Buy bread')
];
}
void main(){
print(TaskData().tasks.indexOf(Task(name: 'Buy milk')));
}
why does it print -1 ?
Flutter(Dart) can not compare objects directly as we compare variables like int, strings and other.
We have to do it manually by checking each and every variables are same or not then we can say that both object are same or not.
However, we can compare class object as other variable by using Equatable package.
Add Equatable package in pubspec.yaml file and then change your class as below. now you will get desire outputs.
class Task extends Equatable {
String name;
bool isDone;
Task({this.name, this.isDone = false});
#override
List<Object> get props => [name, isDone];
}
Your program prints -1 becuase the Task argument you sent to indexOf() does not exist in tasks. The following explanation is dart-related more than it is flutter-related.
By default, instance of an object in Dart is considered equal to another instance only if those are the same instance. Here, you created two different instances, perhaps with the same properties but they are actually independent of each other. In this case both tasks are logically equal but there is no way Dart could know that. Your options are:
Use a const constructor
Const constructors in Dart let you create instances that are compile-time constants. If you use such a constructor, Dart will know for sure that after you create a Task its properties can never change. Thus, it will be comfortable making the assumption that Task(name: 'Buy milk') will always have the same properties of another Task(name: 'Buy milk') no matter what (They are equal). Under the hood, Dart uses the same instance for both. To implement this you'll have to change your code as follows:
class Task {
final String name;
final bool isDone;
const Task({this.name, this.isDone = false});
}
Override the hashCode and the == operator
If you don't want Task to be immutable, you should override the current primitive equality check of Task. from Dart's documentation:
The default hash code implementation provides an identity hash—two
objects generally only have the same hash code if they are the exact
same object. Likewise, the default behavior for == is identity.
If you are overriding ==, it implies you may have different objects
that are considered “equal” by your class. Any two objects that are
equal must have the same hash code. Otherwise, maps and other
hash-based collections will fail to recognize that the two objects are
equivalent.
The default hashCode represents the identity of an instance, but we want it to represent its properties in this case. Note that hashCode should not end up being the same for instances with different properties. It generally does not matter how it's implemented as long as this principle is preserved. I'll use the example provided here to give a possible implementation:
#override
int get hashCode {
int result = 17;
result = 37 * result + name.hashCode;
result = 37 * result + isDone.hashCode;
return result;
}
Now override the == operator to reflect the changes:
#override
bool operator ==(dynamic other) {
if (other is! Task) return false;
Task task = other;
return (task.name == name &&
task.isDone == isDone);
}
}
Note that Dart genrally recommends to avoid defining custom equality for mutable classes, and, following this design rule, the first solution I've listed is the easiest to implement.

Dart: Is there a disadvantage to using const constructor?

There is an analyzer/lint check to warn me when it is possible to use a const constructor: https://dart-lang.github.io/linter/lints/prefer_const_constructors.html
(ie. using final a = const A(); instead of final a = A();)
I think to understand the advantages (there will only ever be one instance with the same constant values for a const constructor). But why isn't this the default? Since dart 2 the new can be omitted, so why didn't they change the definition of creating a new instance which can be created const simply as const instead of new? I assume there must be some disadvantage to having everything const?
(for example in a constant context like const [A()] it is actually the same as const [const A()], so why not everywhere)?
so why didn't they change the definition of creating a new instance which can be created const simply as const instead of new?
If you mean why doesn't final a = A(); automatically assume const A() if A has a const constructor:
Sometimes it is automatic:
const a = A();
in which case A's constructor is being invoked in a const context and doesn't need an extra const qualifier on the right-hand-side.
An explicit const expresses intent. For example, suppose you had:
final a = A(B());
where A and B have const constructors. Later, somebody makes a change:
final a = A(C());
where C does not have a const constructor. If const were automatic, then you would have no idea that a is no longer const. Maybe that's okay, but it also could suddenly have a negative impact on your application's performance, and without an explicit const qualifier, the impact of a local change could have a much wider scope than expected. (That said, explicit const qualifiers and automatically adding them aren't mutually exclusive.)
const can have downsides. const creates compile-time constants. If you have:
final a1 = A();
final a2 = A();
identical(a1, a2) is not true. If const A() were implicit, then identical(a1, a2) would be true, and maybe that's not a property that the code intended to have.
Compile-time constants live forever. The whole point is to have an object that can be reused instead of re-constructing it. The flipside is that won't be destroyed.

What is the difference between immutable and const member functions?

The D programming language reference shows two examples in the Declarations and Type Qualifiers section, so these are both possible:
struct S
{
int method() const
{
//const stuff
}
}
struct S
{
int method() immutable
{
//immutable stuff
}
}
From the docs:
Const member functions are functions that are not allowed to change any part of the object through the member function's this reference.
And:
Immutable member functions are guaranteed that the object and anything referred to by the this reference is immutable.
I've found this question, but all the answers are talking about data types, not storage classes. Same goes for the D const FAQ, even though it's an interesting read.
So what is the difference between the two definitions above? Are there expressions that can replace //const stuff and be legal but not //immutable stuff?
immutable methods may only be called on immutable objects. They can work with the guarantee* that their object (this) will not change, ever.
const methods may be called on const, immutable, or mutable objects. They guarantee that they themselves will not change their object, but other references may change the object.
I'd go with const unless you have a good reason to need immutable, as const functions are callable with all three mutability storage classes.
* At the type system level, anyway. Mutating an immutable object is possible, but causes undefined behavior.

Const member function vs const return type

In D I can specify const functions, like in c++:
struct Person {
string name;
// these two are the same?
const string getConstName() { return name; }
string getConstName2() const { return name; }
}
It seems that the above two are the same meaning. Is it true?
If so how can I return a const string rather than define a const function?
The two are identical. Function attributes can go on either side of a function. e.g.
pure Bar foo() {...}
and
Bar foo() pure {...}
are identical. The same goes for pure, nothrow, const, etc. This is probably fine for most attributes, but it becomes quite annoying when const, immutable, or inout is involved, because they can all affect the return type. In order for those attributes to affect the return type, parens must be used. e.g.
const(Bar) foo() {...}
returns a const Bar, whereas
Bar foo const {...}
and
const Bar foo() {...}
return a mutable Bar, but the member function itself is const. In most cases what you want is probably either
Bar foo() {...}
or
const(Bar) foo() const {...}
since it's frequently the case that having a const member function forces you to return const (particularly if you're returning a member variable), but you can have any combination of const between the member function and its return type just so long as it works with what the function is doing (e.g. returning a mutable reference to a member variable doesn't work from a const function).
Now personally, I wish that putting const on the left-hand side were illegal, particularly when the excuse that all function attributes can go on either side of the function isn't really true anyway (e.g. static, public, and private don't seem to be able to go on the right-hand side), but unfortunately, that's the way it is at this point, and I doubt that it's going to change, because no one has been able to convince Walter Bright that it's a bad idea to let const go on the left.
However, it is generally considered bad practice to put const, immutable, or inout on the left-hand side of the function unless they're using parens and thus affect the return type, precisely because if they're on the left without parens, you immediately have to question whether the programmer who did it meant to modify the function or the return type. So, allowing it on the left is pretty pointless (aside perhaps for generic code, but it's still not worth allowing it IMHO).