I propose a new feature that will make manipulation of value types more efficient, produce more readable code, and encourage greater use of the functional programming style. I disclaim any ownership to this idea.
Currently, there are two C# keywords that allow parameters to be passed by reference, “ref” and “out.” I will confine the discussion to “ref” parameters.
The “ref” keyword has several disadvantages:
- For large value type structures, copying by value is wasteful. It may be more more efficient to passed a structure by reference. One such example of a real world data structure is the Matrix3D data type in WPF.
- The variable passed by reference may be modified by the function.
- The ref keyword must precede all arguments passed to a ref parameter resulting in ugly syntax.
- Only L-values may be passed by reference. L-value are variables and other expressions that may appear in left-hand side of an assignment. These include including locals, field accesses, pointer dereferences, and array element accesses. L-values do not include property accesses, which do not have an identifiable machine address, nor do they include read-only fields, which are restricted by the CLR.
- Ref parameters can not be the target of an extension method. Extension methods calls are expensive for value types, because the “this” parameter is copied by value. This also means that value types can’t have mutable extension methods. This is in direct contrast to instance methods, which pass the value type “this” parameter by reference.
- Ref parameters can not be used in operator overloading functions.
The implementation of an “in” parameter would be very similar to a “ref” parameter.
- The signature of a function with an “in” parameter would be identical to that of an “ref” parameter in MSIL, just as “out” parameters are today. An InAttribute would be applied to an “in” parameter in a manner similar to how the OutAttribute is currently applied to “out” parameters.
- The “in” keyword would not be required at the calling site as “ref” and “out” are currently required today.
- An L-value passed to an “in” parameter would be prevented by the compiler from being modified by the function called.
- R-values could be passed by reference to an “in” parameter. This is one of the benefits of using const references in C#. For instance, one could write Determinant(matrix1 * matrix2 + matrix3)) and the three temporary values would be passed by reference in addition to the three variables.
Other languages such as Ada have an “in” parameter, though I do not know if they behave similarly.
UPDATE: The keyword “in” is very must like “const” references in C++, but it is actually much easier to introduce constness behavior in .NET without the cascading mess of introducing const to other parts of the codebase and libraries.
An “in” variable is not modified if it is passed to another method through an “in” parameter or a regular copy-by-value parameter. It may be modified by an instance method or passage through “ref” and “out” parameter in another method. It’s also modified if any of fields are directly modified in method, possibly through inlining of short methods. After just-in-time compilation, short methods and property accesses are inlined. Simple property getter will become direct field accesses and it would be possible to ascertain whether modifications are made to the data structure.
If there are still potential modifications through instance method calls, the “in” parameter can be copied to a local variable by the compiler before being used. The compiler can prevent modifications to public fields or, alternatively, prevent modifications from propagating to the caller by using a local copy.
An “in” parameter isn’t strictly necessary as the compiler and runtime can already implement copy-by-value this way for large structures. However, the difference in behavior is visible in multithreaded code and through closures containing writable captured variables, if the value referenced is not stored on the stack.