dart-lang / language

Design of the Dart language
Other
2.65k stars 203 forks source link

Variable declaration to be 'final' by default #4117

Open eftihis85 opened 1 week ago

eftihis85 commented 1 week ago

I have observed that in my code the most variables I declare are 'final' and rarely I use some 'non final' variable declaration.

final int id = 1; id = 2 // The final variable 'id' can only be set once.

I would propose the variables in Dart to be final by default without the keyword 'final' before the type of variable. This would save some typing.

int id = 1; id = 2 // The final variable 'id' can only be set once.

It could be introduced the keyword 'mutable' to declare a non-final variable

mutable int id = 1; id = 2 // Accepted

srawlins commented 1 week ago

Thanks for the request! I think this is essentially a duplicate of https://github.com/dart-lang/language/issues/136.

hydro63 commented 1 week ago

Not really possible, it would break pretty much all code, since you are reversing a fundemental behaviour.

PS > there is a way to fix it by analyzing the code and replacing everything correctly when migrating to new version of the language

eftihis85 commented 6 days ago

Thanks for the request! I think this is essentially a duplicate of #136.

I would say it is not the same. I am proposing to "reverse" the way we declare if a variable is mutable or not. From personal experience, the vast majority of the variables declared need to be immutable. Thus it makes sense to consider make the declaration of the immutable variables more concise, shorter and simpler.

Proposed "immutable" variable declaration: int id = 1;

Proposed "mutable" variable declaration: mutable int id = 1;

This is a practice that is used by functional languages and Dart has many functional characteristics.

julemand101 commented 6 days ago

The cost of this language suggestion are huge since it will break nearly every single project which are going to target the Dart version that includes this change. Yes, it can most likely be fixed with some automation but it is still something every project needs to do.

And when looking at the cost, it is very difficult to argue that we are gaining enough "value" for that cost we are asking all developers to put into this change.

The way Dart works here are similar to the programming languages it is inspired by like Java and C#. So it is as equally valid to have the opinion that the current way is the right way. So asking developers to make this change to their code bases while maybe also disagree with the change... that is painful.

Down vote from me.

eftihis85 commented 6 days ago

Not really possible, it would break pretty much all code, since you are reversing a fundemental behaviour.

PS > there is a way to fix it by analyzing the code and replacing everything correctly when migrating to new version of the language

I imagen that the migration process is pretty simple and safe. This is also a reply to the comment above from [julemand101].

julemand101 commented 6 days ago

Not really possible, it would break pretty much all code, since you are reversing a fundemental behaviour.

PS > there is a way to fix it by analyzing the code and replacing everything correctly when migrating to new version of the language

I imagen that the migration process is pretty simple and safe. This is also a reply to the comment above from [julemand101].

You are still asking all projects to need run some tooling and do a commit across all their files... This is not something we have a tradition for in Dart besides null-safety which was painful for many projects even with tooling.

The value proposition does not make much sense here since current behavior are not even considered a problem that needs to be solved, to gain some developer benefit that are remotely close to the amount of work we will put on projects to be converted.

Whish issues are we trying to solve which we have today with typed variables being mutable by default?

Which patterns become more tedious with the change? E.g. for loops could become more annoying since we need to specify initial variables to be mutable.

hydro63 commented 6 days ago

I am for #136 proposal of adding a := operator for short final declaration, rather than completely redesigning the language to work in a way it isn't supposed to. It's short, concise, and doesn't break anything. It also follows a principle of breaking as little as possible, while still delivering a good and usable feature (very important in language design).

also while replacing everything might seem easy, there are a lot of edge cases (like final in function parameters), that make it prone to errors. it is also true that you are forcing basically every single developer to fix the problems that would occur during the migration. Solving migration bugs causes a lot of headaches, and possibly other bugs related to the mutabilty of the variable would appear.

TLDR > the := is better IMO solution for immutability, since then the final declaration is actually shorter than mutable declaration.

myFinal := 5;
var myMutable = 5;
lrhn commented 5 days ago

Null-safety was painful because the migration could not be automated. The new feature added (nullability-)information to the language that old programs didn't have, and new programs required. The migration was to add that information to the program, correctly and consistently. (The only possible fully-automatic migration would have been to change all types to TheType? and all invocations to be prefixed by !. That would preserve the semantics, but boy would it be ugly.)

This migration would be fully automatic. No new information is added, the existing information is just represented in a different way. I don't think it's technically impossible to do this change. But the effort, even if automated, is probably not worth it.

eftihis85 commented 4 days ago

In my opinion we should always aim to make more decluttered code. It is a benefit compounds through time but it is not measurable. I also asses that this migration can be fully automated. The same can be done with the 'required' for the named parameters for the constructor.

Wdestroier commented 17 hours ago

Considering I use inference most of the time, changing int id = 1; to mean final int id = 1; would not help (possibly make it worse), because I would still write either var id = 1; or final id = 1;. I agree with @hydro63, x := 1; would be a great improvement over final x = 1; (5 lessen characters). Other than that, the current language behavior is perfect.

ykmnkmi commented 17 hours ago

Some developers (me too) use final only for class and top-level library fields, not for function variables.

Wdestroier commented 15 hours ago

Some developers (me too) use final for top-level library fields

You could write myTopField := value; instead of final myTopField = value; . That's an improvement for you too, right?

Some developers (me too) use final only for class

A class-level const modifier or an annotation implying constructors and properties are const/final would be useful, specially for Flutter widgets, but I prefer to have mutable classes when unspecified. I wonder why Dart doesn't have this feature.

Some developers (me too) do not use final for function variables.

Is the current behavior great then? You can write int x = 0; or var x = 0; and both are short enough. Changing the behavior (issue title) would require you to write extra code in the former case.

ykmnkmi commented 14 hours ago

@Wdestroier writing extra keyword is no for me; := seems more usable (thanks to Go and Python). But what about late final variables?

Some developers use final for arguments. By default, all arguments are reassignable. With this proposal, do I need to write an extra keyword for arguments?

Wdestroier commented 13 hours ago

But what about late final variables?

The syntax would be late property := value; I guess, and the same for static. Lasse proposed this syntax in the other issue, maybe he can confirm this, but the transition looks natural.

By default, all arguments are reassignable. With this proposal, do I need to write an extra keyword for arguments?

The issue description only mentions variables, @eftihis85 would need to confirm. I think so, considering parameter values are changed less often than variables.

hydro63 commented 13 hours ago

@ykmnkmi

But what about late final variables?

There would be absolutely no differerence compared to now. The := would only work on final assigment, not final declaration. As for final parameters, it would be possible to use := in optional and named parameters.

late final int x;
x = 5;

y := 5; // operator := is only alias for final x = expression; not late final

void func(final int arg);
void func([arg := 5]);
void func({arg := 5});
eftihis85 commented 12 hours ago

The issue description only mentions variables, @eftihis85 would need to confirm. I think so, considering parameter values are changed less often than variables.

I was writing about changing the notion to declare variables. The proposal was to make all the variables to be final by default without the need to write the 'final' keyword.

Later I added a comment for the named arguments in the class constructor to be as default required without the need to write the 'required' keyword.

Some points as a response to the comments above. 1) since the style we code nowadays is using many more times final variables then this should be the default. Without any extra key words. If change the notion := is an unnecessary solution, the same way final or required keywords are. 2) := is good when you write, bad when you read as it is a small abbreviation. Imagine how you react when you read codem and you are tired. all these small symbols make it difficult.