-
Notifications
You must be signed in to change notification settings - Fork 1k
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
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
Champion "readonly for locals and parameters" #188
Comments
Any plan for readonly types(classes and structs)? |
should support readonly i = 0; // shorthand for readonly var
const j = 0; // shorthand for const var |
Wasn't |
@jnm2 I just don't like the idea of adding new keyword. Especially it is already have keyword in the language that has the same meaning
At least I have seen some suggestion to use Especially because |
@Thaina Yes, I'm inclined to agree. |
And you could continue to. Like Although I do prefer |
Oh yes! |
@HaloFour It not breaking change I understand but it still ambiguous BTW I still don't like |
|
Personally the latter reason is enough for me. It's already a contextual keyword, and in that existing context it creates a readonly identifier. |
Fair enough 😄 |
Do you mean immutable types? If so, that's a completely separate proposal (I'm pretty sure it's been made before). |
ITNOA @Richiban where I can found it? |
That's a new one! dotnet/roslyn#7626 and https://github.com/dotnet/roslyn/issues/159 are probably what you're looking for. |
Something I like about final String name;
if (entity instanceof Person) {
Person person = (Person)person;
name = person.getFirstName() + " " + person.getLastName();
}
else if (entity instanceof Company) {
Company company = (Company)company;
name = company.getFirmName();
} This can be useful in those scenarios where you want the local to be readonly, the expression to calculate it can throw and you want the scope of the local to exist beyond a |
@Richiban thanks, but I hope to see comprehensive proposal about immutable object in csharplang project. |
@HaloFour Is conditional operator ( ?: ) not sufficient for this purpose? |
Sometimes not. I amended my comment to mention Either way, Java supports this, and I make use of it frequently enough that I think it would be useful here. |
I think simple rule like "All local |
That's yet another use-case for let name = entity match (
case Person person : $"{person.FirstName} {person.LastName}",
case Company company : company.FirmName
); |
We may differ on opinion there. If the expression has to be overly complex in order to satisfy an overly strict language feature that only decreases overall maintainability and readability. I'd rather the flow be logical and the compiler enforce readonly-ness where appropriate. And as a Java programmer who works directly with hundreds of other Java programmers I can say that this has never been a source of confusion. It's a pattern used fairly frequently across the Java ecosystem. If anything I think I would find it much more annoying that I couldn't declare and assign a It's just one exceptionally simple case. |
I lose track of the twists and turns of these arguments, but what is the reason why we can't treat this like NRTs and introduce an optional |
I don't consider it a mistake. I think it's fine and expected that method bodies be mutable. Within the method is where I do the work. Building up scratch data and whatnot. In terms of numbers too, we see an insane amount of bugs caused by null (thousands in my career). But several orders of magnitude less for mutable variables. I think it's happened like once or twice in the same time. I don't view it as a mistake. I view it as the normal, reasonable, effective way to code. |
The normal reason that we don't like introducing dialects. We did it for nrt because the problem was huge and the gain was worth it. We don't see that with this issue. First, we don't even have data indicating there is a problem. So introducing a dialect for a non-issue seems unnecessary. |
Note: hidden struct copies are a performance hit and logical failure that is only solved by those who know they exist. Immutable structs by default would help there. |
I refer you to the first quote. 😖 |
Yes... what's the problem with teh first line. Mutation in methods is the normal, reasonable, and effective way to code. That's how we see methods in teh first place. They are the place where you do work, and that involves performing computation, storing values in temps, mutating as appropriate, then returning a result. I'm a big fan of immutable values flowing between methods. But within a method, i don't see value in forcing readonlyness or immutability. |
I don't disagree that mutability is a problem with an associated cost. But that cost is many, many times fewer orders of magnitude than the problems associated with The cost of mutability isn't a single value, either. A mutable local has extremely little cost associated with it. A captured mutable local is a different story, as now that mutable state could potentially be shared, although the scoping is quite limited. A captured primary constructor parameter has a much wider scope, so now you have the potential of shared state visible across multiple threads. Say the LDM decided to just implement this feature, and allow |
This isn't strictly correct and is entirely dependent on the size of the struct, how its used, and many other factors. Immutable structs likewise do not prevent copies, in fact they often do the exact opposite and encourage copies to be created instead. For data that can be enregistered, immutable is often good and beneficial. This applies largely to ABI primitives such as However, for data that cannot be enregistered such as due to it being "too large" (typically anything over A lot of performant code therefore explicitly opts for mutability of locals accordingly, specifically because it allows more control of the storage locations and the developer to explicitly codify the semantics they intend. This can be especially beneficial in the face of enregistration or even field promotion. Appropriate usage of mutable locals, including parameters, is often key to optimizing core functions and limiting the amount of work the compiler has to do to understand the code. |
Now with that being said, some advanced immutable first languages (like Rust) do a lot of backend work to convert your seemingly immutable and functional-like code into a mutable, imperative model that suits how the computer actual operates. It does this by having first class integration of features and syntax that allows the compiler to better understand the application and do the type of advanced cross method optimizations that allow the efficient thing to actually happen and to happen safely. |
Exactly. I'm genuinely trying to find any data indicating there is any sort of significant issue with bugs due to non-readonlyness, or issues with understanding methods with mutable variables. I can't find anything indicating this is actually valuable for code. And, as has been mentioned a few times, this would now add a lot of noise for very little benefit. That is not a benefit to the language. |
I would argue that shallow immutablity (readonlyness) is useful mostly for the developer, in order to protect from silly mistakes. As far as yesterday I found in my code a mistake: I was modifying a wrong local variable by mistake inside some if-branch. Readonly would have prevented this bug. So the advantage is not efficiency but ease of reasoning about the code. |
Right. The issue is that we don't see this mistake happening much in the wild. As such, making a heavyweight, noisy, feature like this to prevent it is not palatable. We recommend that if this is not something you want, you write an analyzer for this purpose. |
Well, I cannot speak for the majority of C# users, but I find myself often in a position where I would prefer having readonlyness available. It must not be necessarily noisy, a simple |
That scenario is more common than you think |
Which can only ever solve for one particular use case, namely inferred locals. It doesn't help with parameters, and it doesn't help for anyone who prefers to not use type inference. There are no options to make it not noisy from the language perspective, aside creating a dialect. |
@HaloFour |
The language team disagrees with you. It's an additional modifier which, for the folks that want this feature, would end up added to the vast majority of all declarations. That is noisy. The fact that it's 3 characters instead of 8 doesn't really change that. |
@HaloFour If the alternative is no readonly for locals at all, I would prefer "noisy" 3 characters. Perfect is the enemy of good. |
@HaloFour |
The alternative is an analyzer, so you can choose whether you want locals to be treated as readonly by default, as an analyzer is allowed to make decisions that the language won't. |
@HaloFour Analyzer is a poor man's alternative (which is, well, better than nothing). This alternative would create a non-standard language dialect, developers will need to learn how to apply the needed analyzer, how to fight its bugs, how to cancel the readonlyness for cases where it's not intended and so on. In some organizations this would create an additional SOUP item. |
It doesn't create a dialect, it limits what you can do within the standard language. This is no different from StyleCop or any of the other tools routinely used by organizations to enforce code hygiene. It's infinitely cheaper than a language change and addresses all of these concerns, including the ability to flip the default, or to enforce in some situations and not others. |
In the interest of making the language team's position on this clear, we've decided to close this issue, mark it |
This issue was moved to a discussion.
You can continue the conversation there. Go to discussion →
See also dotnet/roslyn#115
Design review
The text was updated successfully, but these errors were encountered: