From 7c69baba8f1c16de7317243375bf767eaf8713a1 Mon Sep 17 00:00:00 2001 From: Yaakov Date: Tue, 9 Oct 2018 21:07:42 +1100 Subject: [PATCH] Replace weird quote character with regular single quote --- proposals/readonly_locals.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/proposals/readonly_locals.md b/proposals/readonly_locals.md index 00a3d8f..0a3c283 100644 --- a/proposals/readonly_locals.md +++ b/proposals/readonly_locals.md @@ -15,27 +15,27 @@ Allow locals and parameters to be annotated as readonly in order to prevent shal Today, the `readonly` keyword can be applied to fields; this has the effect of ensuring that a field can only be written to during construction (static construction in the case of a static field, or instance construction in the case of an instance field), -which helps developers avoid mistakes by accidentally overwriting state which should not be modified. But fields aren’t the only places developers -want to ensure that values aren’t mutated. In particular, it’s common to create a local variable to store temporary state, and accidentally updating +which helps developers avoid mistakes by accidentally overwriting state which should not be modified. But fields aren't the only places developers +want to ensure that values aren't mutated. In particular, it's common to create a local variable to store temporary state, and accidentally updating that temporary state can result in erroneous calculations and other such bugs, especially when such "locals" are captured in lambdas, at which point they are lifted to fields, but there's no way today to mark such lifted fields as 'readonly`. ## Detailed design [design]: #detailed-design -Locals will be annotatable as `readonly` as well, with the compiler ensuring that they’re only set at the time of declaration (certain locals in C# are -already implicitly readonly, such as the iteration variable in a ‘foreach’ loop or the used variable in a ‘using’ block, but currently a developer has +Locals will be annotatable as `readonly` as well, with the compiler ensuring that they're only set at the time of declaration (certain locals in C# are +already implicitly readonly, such as the iteration variable in a 'foreach' loop or the used variable in a 'using' block, but currently a developer has no ability to mark other locals as `readonly`). Such `readonly` locals must have an initializer: ``` C# readonly long maxBytesToDelete = (stream.LimitBytes - stream.MaxBytes) / 10; ... -maxBytesToDelete = 0; // Error: can’t assign to readonly locals outside of declaration +maxBytesToDelete = 0; // Error: can't assign to readonly locals outside of declaration ``` And as shorthand for `readonly var`, the existing contextual keyword `let` may be used, e.g. ```C# let maxBytesToDelete = (stream.LimitBytes - stream.MaxBytes) / 10; ... -maxBytesToDelete = 0; // Error: can’t assign to readonly locals outside of declaration +maxBytesToDelete = 0; // Error: can't assign to readonly locals outside of declaration ``` There are no special constraints for what the initializer can be, and can be anything currently valid as an initializer for locals, e.g. ```C# @@ -43,27 +43,27 @@ readonly T data = arg1 ?? arg2; ``` `readonly` on locals is particularly valuable when working with lambdas and closures. When an anonymous method or lambda accesses local state from the enclosing scope, -that state is captured into a closure by the compiler, which is represented by a “display class.” Each “local” that’s captured is a field in this class, yet +that state is captured into a closure by the compiler, which is represented by a 'display class.' Each 'local' that's captured is a field in this class, yet because the compiler is generating this field on your behalf, you have no opportunity to annotate it as `readonly` in order to prevent the lambda from erroneously -writing to the “local” (in quotes because it’s really not a local, at least not in the resulting MSIL). With `readonly` locals, the compiler can prevent the lambda +writing to the 'local' (in quotes because it's really not a local, at least not in the resulting MSIL). With `readonly` locals, the compiler can prevent the lambda from writing to local, which is particularly valuable in scenarios involving multithreading where an erroneous write could result in a dangerous but rare and hard-to-find concurrency bug. ``` C# readonly long index = ...; Parallel.ForEach(data, item => { T element = item[index]; - index = 0; // Error: can’t assign to readonly locals outside of declaration + index = 0; // Error: can't assign to readonly locals outside of declaration }); ``` As a special form of local, parameters will also be annotatable as `readonly`. This would have no effect on what the caller of the method is able to pass to the -parameter (just as there’s no constraint on what values may be stored into a `readonly` field), but as with any `readonly` local, the compiler would prohibit code +parameter (just as there's no constraint on what values may be stored into a `readonly` field), but as with any `readonly` local, the compiler would prohibit code from writing to the parameter after declaration, which means the body of the method is prohibited from writing to the parameter. ``` C# public void Update(readonly int index = 0) // Default values are ok though not required { ... - index = 0; // Error: can’t assign to readonly parameters + index = 0; // Error: can't assign to readonly parameters ... } ```