Reputation: 857
Effective dart specifies that top-level variables should be final
when applicable:
https://dart-lang.github.io/linter/lints/prefer_final_fields.html
However, I could not find any information about method parameters.
Flutter repo's code functions are mostly ones with parameters not marked final
, that includes all the overridden build
methods I've seen.
Which of the following is better in terms of performance and app weight:
@override build(context)
@override build(BuildContext context)
@override build(final BuildContext context)
Perhaps overridden functions should be defined the same way as the super function? Is there any difference between overridden functions like build
above which can infer the type, and other named/unnamed functions (other than not setting the type makes the variable dynamic), which Flutter repo also writes this way:
static double _flingDistancePenetration(double t) { // t is not final, although treated as immutable
return (1.2 * t * t * t) - (3.27 * t * t) + (_initialVelocityPenetration * t);
}
I've seen this question about Java: Why would one mark local variables and method parameters as "final" in Java?, and, while I agree with the top answer, I'm completely in the dark about why does Flutter repo not do that.
Upvotes: 5
Views: 1655
Reputation: 90005
Regarding parameter types: yes, always include them. Otherwise your parameter is likely to be dynamic
1, which incurs runtime overhead and no type safety. You also want your API to clearly specify what argument types it expects.
Regarding final
: That is an opinion-based question, and my opinion is that while I agree with the prefer_final_fields
lint, I disagree with the prefer_final_locals
lint. I think that adding final
for local variables (including function/method parameters) is pointless.
Contrary to what the top-voted answer to the related Java question says, any half-decent compiler should be able to easily determine whether a local variable is reassigned. If there's any optimization opportunity there, the compiler should be able to do it for you.
In languages such as Dart where implementation usually is inline with the interface (as opposed to languages such as C or C++, which have separate header files to declare interfaces), adding final
to parameters is visual noise. It provides no useful information to callers.
You shouldn't unilaterally mark all function/method parameters as final
anyway. Sometimes reassigning parameters is appropriate. For example, if your function needs to perform some sort of normalization on its arguments:
void foo(File file) {
file = file.absolute;
...
}
in such a case, using a final File file
would mean you'd need a separate local variable for the normalized version, and now the code would be error-prone since it could accidentally use the original variable.
final
for a field is an important part of an API. It tells callers that the field will not be reassigned; the object referred to by the field will always be the same object. final
for local variables and for function/method parameters affects only the person implementing the function. If the implementor doesn't want to reassign a variable, they can choose to simply not reassign it.
Some people will claim that having final
local variables helps code readability since they know that the variable will not be reassigned. However, I instead think that final
can be misleading since it says only that a variable cannot be reassigned, not that it won't be mutated, and knowing the latter is much more important.
1 For overridden methods, parameter types are constrained by the corresponding parameter types declared by the base class. Therefore omitting a parameter type in an overridden method will use the parameter type from the base class.
Upvotes: 7
Reputation: 11210
Answer to the author of the question.
Examples:
foo(Baz baz)
void main(List<String> args)
An exception to these rules.
dynamic
foo(Baz baz, bar)
list.sort((x, y) => x.compareTo(y))
Some useful information:
From Dart specification:
Dart Programming Language Specification
5th edition draft
Version 2.2
A final variable
is a variable whose binding is fixed upon initialization; a final
variable v
will always refer
to the same object
after v
has been initialized. A variable is final
iff its declaration includes the modifier final
or the modifier const
. A mutable
variable is a variable which is not final
.
Variable immutability
does not make an object immutable
in Dart.
This is a very common misconception when variable immutability
is confused with object immutability
.
P.S.
A common misconception is that Dart users get the impression that function parameters in Dart are passed by reference.
This is not true.
Parameters are passed by value (not by reference).
But due to the fact that (as indicated in the specification) any variable already contains a reference (refers) to the object (but not the object itself), in fact, this reference is passed, by value (as normal value).
That is, a value is passed, but the value itself is of the Referernce
type, which is indicated in the language specification.
From Dart specification:
a final variable v will always refer to the same object
That is, the variable stores the reference
, but not the value
itself.
It is this reference
that is passed by value
, because there is no reason to pass this reference
by reference.
Upvotes: 2