Skip to content

Latest commit

 

History

History
115 lines (75 loc) · 6.16 KB

readonly-parameters.md

File metadata and controls

115 lines (75 loc) · 6.16 KB

Readonly Parameters

Summary

We allow parameters to be marked with readonly. This disallows them from being assigned to or being passed by ref or out.

Motivation

C# users have long requested the ability to mark both locals and parameters as readonly. The design team has somewhat resisted this for two reasons:

  • The view that readonly on parameters and locals would be an attractive nuisance more than a helpful addition.
  • Indecision on what a succinct syntax for locals would be to minimize the nuisance part of the first objection.

However, the addition of primary constructor parameters changes that calculus, at least for parameters. A significant piece of feedback from the initial preview is that users would like to be able to ensure that primary constructor parameters are not modified. The scope of such parameters is much larger, so the danger of accidental modification is much higher. We therefore propose allowing readonly as a parameter modifier.

This proposal makes a few assumptions about readonly locals as part of it:

  • A future design would allow readonly as a local modifier.
  • That future design might allow a shorthand for readonly var, or may say that readonly var is not allowed, and the separate shorthand is required for a readonly type-inferred local. What that shorthand is (val, let, const, or some other keyword) is beyond the scope of this proposal.

These assumptions allow us to presume that to fully spell out readonlyness for a parameter or local requires a modifier, and that modifier is readonly. In places where types can be inferred, we offer a shorthand that combines the meanings, but otherwise readonly is required.

Detailed design

Syntax

We modify section 15.6.2.1 of the C# specification with the following new definition for parameter_modifier:

parameter_modifier
    : parameter_mode_modifier
    | 'this'
    | 'readonly'
    ;

The spec is not yet updated to include the draft C# 12 specification for ref readonly parameters, but we will restrict readonly such that if a parameter is both readonly and ref readonly, the readonly must appear on the left side of the ref readonly, so that readonly ref readonly is permitted, but ref readonly readonly is not.

Semantics

For a readonly parameter, the compiler will issue an error when it is assigned to or taken as a mutable lvalue. This means that a readonly parameter cannot be passed by out or ref, but can be passed by value, ref readonly, or in.

partial methods

For partial methods, we allow the implementing partial method declaration to add the readonly modifier to a parameter if the defining partial method did not. If the defining partial method included the readonly modifier, the implementing partial method must also include it.

Signature-only locations

abstract members, interface members, delegate types, and function pointer types are not permitted to specify readonly on their parameters

Overriding

Overriding members are not required to match the readonlyness of overridden member's parameters. readonly may be added or removed with no effect on the program.

Lambda parameters

Unresolved question

Emit

The presence of readonly on a parameter has no impact to the generated code. It is not possible to determine from metadata whether a parameter is readonly or not.

Drawbacks

Earlier the proposal alluded to this feature being an attractive nuisance. To spell it out more clearly, we are worried that by introducing a verbose modifier that many people would like to be the default (including ourselves!), it will become the new "thing to do" on every method definition, even in cases when it provides no real safety benefits.

Alternatives

The championed issue has a number of alternative designs, but most center around the axis of: should we introduce a new, shorter modifier, or a shorthand that can apply to both locals and parameters? For example, val int i as a parameter definition would be what this proposal calls readonly int i. This shorthand is very inconsistent with standard C# behavior, so this proposal takes the position that we would only want to introduce a shorthand for the readonly + type inference case.

Unresolved questions

Restrict to just primary ctor parameters

This general feature has historically been pushed back on due to the attractive nuisanceness of the feature. We could artificially restrict this to just primary constructor parameters to avoid introducing that in general.

Lambda parameters

Today, when applying a modifier to a lambda parameter, the type must also be spelled out. For example, this is not permitted:

delegate void D(ref int i);
D d = (ref i) => {};

The LDM has long thought about allowing the type here to be omitted, but has not yet done so. Should we make that change as part of this proposal? Or should we say that readonly, like ref, means that the type of the lambda parameter must be spelled out?

Emit consequences

This proposal states that readonly on parameters has no effect on the emitted code, and that it will not be possible to tell from metadata (including things that read metadata, such as reflection) that a parameter was declared as readonly. Are there use cases for reflecting this information in metadata, and if so, what should the emit strategy we use to convey this information be? And, if we do emit to metadata, should that change how overriding carries through that information?