-
Notifications
You must be signed in to change notification settings - Fork 209
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The final
keyword is too long
#136
Comments
FWIW, I can report my personal experiences here. I've been using final inferred variables for some time now (all my repos have the However, there is one place where I would love to use final variables, but can't bring myself to use the keyword because it is just too verbose: function parameters. The additionaly six characters per parameter clutter the signature with keywords that establish a constraint most programmers assume anyways (see the lints: |
|
I like |
I think a bigger problem with String foo = readFoo(); // final by default
final foo = readFoo(); // same thing but infers type
var String foo = readFoo(); // foo is mutable
var foo = readFoo(); // type inference This would also solve @pschiffmann's problem with function parameters. Also, I agree with @zoechi that |
Note that |
Dart is enough of a distinct entity to JavaScript that it's usage re Also, JavaScript devs may appreciate a succinct |
So |
It'd be neat if you could opt-in to making
|
Swift also uses |
Swift Is this proposal about a shorter lhs binding keyword or about a broader story re immutablity? Personally just think lhs binding is appropriate. |
It's about the binding of the new declared name to an object. That object may be mutable. For immutability of instances, check #125. |
@mraleph I wouldn't be worried about JS semantics at all. Over there the @peldritch Swift does not make the rhs immutable. The following is valid Swift code: class Mutable {
var message: String = ""
}
let m = Mutable()
m.message = "What's up?" // totally OK
// What it doesn't let you do is rebind the variable:
m = Mutable() // ERROR This is also the semantic we want in Dart. |
Right, Swift |
Hold on, can Dart do that? 🤔 |
Likes and dislikes are not very important for the sane language design, especially if you cannot justify them. Most variables are "final", and only minority are vars. It is absolutely illogical for the common case to stand out! But for the rare case it may be a desirable property. |
It might make more sense to rename (edit: i'm kinda joking, just use |
That depends on how much change is possible. I'd prefer #136 (comment) any time.
I think I did. |
There are a few separate concerns here that I think should be teased apart:
The first point is observably empirically true. But it's not clear to me that the latter two are, at the level of local variables. There are a lot of intents that a programmer could write down for later programmers to know, and some of those could be mechanically verified by the analyzer. For example:
With all of these, the question isn't "is the intent useful?" It's whether the intent useful enough to:
For local variables, it's not clear to me that it's actually a net productivity gain to track which ones can be assigned and which can't. The variable is already local, so its scope is relatively small. It's often only a second's glance to tell if it is reassigned. Most editors will show all uses of a variable when you hover over it. I do wish we had a shorter keyword for single assignment variables. (I pushed for And, in general, I think it's important that we make a distinction between what the code the user wrote happens to do and what they intend it to be able to do. If I write a class and don't give it a private generative constructor, that doesn't necessarily mean I intend for users to subclass it. I may have simply not bothered to author any intent one way or the other. I think that's likely true of almost all uses of |
In Flutter we've been enforcing the use of I wish we could opt-in (on a per-file or per-library basis) to making |
+1 on the value of seeing at declaration time whether a variable may be reassigned. I certainly can scan down a function looking for assignments, but when I'm trying to wrap my head around new code I do not find it a drawback to need to go back and remove a |
FYI, just filed related #160 (if immutable shared objects also support sharing closures then the ergonomics of |
One wrinkle with pushing towards single assignment locals by default is parameters. Even if we get
Scala, Kotlin, and Swift all treat parameters as single-assignment. They also all had ways to out of that which they then later deprecated and removed so that parameters are only single-assignment. That's a strong signal that it would be the right behavior for Dart if we moved to a shorter local variable keyword and encouraged everyone to use it. However, that would also be a massively breaking change. It's an automatically toolable one, but still. :-/ |
Do you have any links to more details on that? I'd love to read about these changes. |
Those seem like pretty compelling arguments, I'm sold. |
The IDE could use syntax highlighting to tell you whether a variable is reassigned, with no help needed from the developer. This is trivial to implement--I've done it--but unfortunately it requires a new version of the analyzer<-->IDE protocol, so it's breaking change, and the analyzer team wanted to wait for more new features to justify making a breaking change. As far as I'm aware there haven't been any others in ~years, though, so maybe it's time. |
IDE's don't help when you're trying to understand the code in a YouTube video or on a slide at a conference or whatnot. |
No, it's because sometimes inference will give you a type you don't want - for example one that's too specific: abstract class Node {
Node? get parent;
Node? ancestorThat(bool Function(Node) matches) {
var current = this; // Inferred as `Node`.
while (current != null) {
if (matches(current)) {
break;
}
current = current.parent; // Error; can't assign `Node?` to `Node`.
}
return current;
}
} One solution here is to widen the type of current with a type annotation to allow null: Node? current = this; |
@leonsenft same cases, sometimes I'm looking for feature like this var? current = this; |
I don't think we should make non-final look more confusing than it is today. Final by default, meaning a few extra letters for non-final, is fine, but I don't see the value in a punctuation symbol over |
I'd say final is fine... It is only annoying in Java, because you need to write |
This isn't true... A |
The variable won't vary, what will vary is the class instance field value. class Text { // Text is a class that explicitly extends
// the Object class, thus it is an object.
String value; // value is a field, String is the field type.
Text(this.value);
}
void main() {
// name is a variable.
var name;
// new Text is a class instance
name = Text('Gates');
// The Text class instance is not immutable.
// Because it contains fields that can have their value changed.
(name as Text).value = 'Steve';
} Take as example the following line, which is valid code in Dart: var name; This line declares a variable reference called "name". This variable may reference a mutable or an immutable object instance. var name = const Text('John'); // the var keyword is not related to what it references. If the |
Depending on context, the word "immutable" often carries connotations of deep immutability. That said, we're talking about Dart |
It would be nice even just to shorten final to fin. |
If Dart would go with |
val is too close to var lexically. I don't think it needs to be shortened personally, it's quite expressive as is. I'd be fine with it be the default but it does not really matter to me except for parameters.
Maybe for cases where you do want super type. eg The case where I use both is with late, and it's quite long indeed |
Hello, I think dart 3 is a good opportunity to move to " And instead of promoting dart 3, as a mere null-safety release, we would be eligible for the full fledged "safer language" promotion, Also i read in some issue (on any one of
Which does NOT sound like great, and actually makes the first impression, maybe not bad, but less good, than something like "Safer language"(a claim, backed by final-by-default, and sound-null-safety), just my opinion, |
Also, I have a question, Why cannot,
thanks again, |
Too late for Dart 3 to add another major feature. I too would vote for "final by default", as I've suggest up-thread, but it's not a small change. It requires migrating all code in the world. (Again!) Making Making Also, whether var c1 = ConstantConstructor(const []); // Would be implicitly `const`?
var c2 = const ConstantConstructor([]); // Is explicitly `const`.
var c3 = ConstantConstructor([]); // Would not be implicitly `const`, because the argument is not constant. It would be easy to take a big constant structure like And you wouldn't notice, because it still runs, it just allocates a lot more, mostly indistinguishable, objects. We considered this at some point, and decided that the risks were too big, and it's better to make you always write at least one |
final is too long, but I hate
|
Maybe this topic has already changed topics, but based on the title I am writing my opinion. When I read this title, I thought it would be nice if the variables were final from the beginning, but then I would have to write the type instead of On the other hand, I would not like to see strange syntax added. ( |
If we take this issue to the extreme, I think an argument could be made that other keywords like Here's perhaps an unpopular opinion: I think that the approach that Dart takes is far superior to all the alternatives proposed in this issue.
I agree that the ability to write those keywords quicker would make developers slightly more productive when writing code. But if the goal is to reduce keystrokes, then I'd recommend the pattern that is known as the hyper key on macos (hyper key via karabiner elements / hyper key via better touch tool). It allows you to reassign caps lock to a new modifier. That way you can get your keystrokes down to 2 keys (e.g. |
This comment was marked as resolved.
This comment was marked as resolved.
This would be similar to the approach taken by Go, with short variable declarations. Those are only allowed in function blocks, also. Thinking about it more, I prefer this approach, as it doesn't modify any existing language concepts (like |
Also:
[Removed ] ** More analytically, one could argue the compiler is the true audience for the *** I believe |
Not a fan of
|
Let expressions - as defined by the team, are great, and will help in the move away from If the team thinks https://dart-review.googlesource.com/c/sdk/+/322841 |
I see those two CLs are currently abandoned. What are the next steps for this? |
Adding let x = func();
let x = transform(x);
// vs having to do
final y = func();
final yTransformed = transform(y); |
It's inconvenient that declaring final variables require more typing than non-final variables. This discourages the use of final variables.
Even with inferred types, it's shorter, and if you want to specify the type, it gets even longer:
While final variables are not strictly necessary (if you don't assign to a variable, it doesn't matter semantically whether it's declared final or not), some people prefer a style where you make variables final unless they need to be mutable, and Dart does not support that writing style very well.
See #135 for one suggestion which improves the experience for inferred variables by replacing
final
withval
. It doesn't improve the typed case. It requires adding a new built-in identifier (but likely not a reserved word).Another option could be using
:=
for final initialization (since final local variables need to be initialized):This doesn't work for instance variables since they may be intialized by a constructor, or parameters, and to keep requiring the
final
word for instance variables and parameters, and using:=
everywhere else, is inconsistent.The text was updated successfully, but these errors were encountered: