[Proposal] Allow local functions in constructor to modify readonly fields #1873
Replies: 13 comments
-
What would happen if you attempted to expose the local function outside of the constructor? E.g.: private readonly int X;
private Action action;
public Foo()
{
action = InitB;
void InitB() => X = 1; // Currently doesn't work
} |
Beta Was this translation helpful? Give feedback.
-
Conceptually, I quite like this - but I wonder how this would actually be implemented, given that local functions are (I believe) actually implemented as private methods with unprintable names. |
Beta Was this translation helpful? Give feedback.
-
At that point, why not inline the local functions? One of the motivating examples was sharing initialization logic between constructors, too. |
Beta Was this translation helpful? Give feedback.
-
You actually can initialize a read-only field in a function if you pass it by ref: class Foo
{
private readonly int X;
public Foo()
{
InitB(ref X); // works
}
private void InitB(ref int X) => X = 1;
} So I guess this feature could be implemented as syntactic sugar withouth CLR changes. But I doubt the syntactic sugar is worth the cost here ... |
Beta Was this translation helpful? Give feedback.
-
A problem occurs if that constructor also happens to contain a lambda which encloses over the local state. In that case the parameters/fields are lifted into a display class along with the bodies of both the lambda and the local function. It's the kind of caveat that probably makes it not worth attempting to spec out or implement. |
Beta Was this translation helpful? Give feedback.
-
@theunrepentantgeek That's exactly my issue as well, C# does move them outside and changes the name. public void Outer()
{
void Inner(){ }
} Compiles into: public void Outer() { }
[CompilerGenerated]
internal static void <Outer>g__Inner|0_0() { } So the name keeps track of the method top-most parent function, so if I defined a method inside of If it's the constructor, however, the being of the local function name isn't |
Beta Was this translation helpful? Give feedback.
-
@jnm2 Well, you wouldn't inline because if the constructor is very long, you might want to condense it into functions, as is the good practice and improves readiblity, even if you only use them once. However, in constructors, that then means not being able to assign readonly fields, so you're forced to deal with less readible code. Also, you might want to use the same local function multiple times in the constructor. Yes this doesn't solve the problem with sharing logic between constructors but I think it should be a feature regardless because the absence of it is counter intuitive. |
Beta Was this translation helpful? Give feedback.
-
@popcatalin81 What cost are you talking about? Also, see my reply to theunrepentantgeek, where I mention that all local and nested local functions, inside the constructor, and only them, start with |
Beta Was this translation helpful? Give feedback.
-
@svick Good point. I guess a few things could happen:
|
Beta Was this translation helpful? Give feedback.
-
Any writes to an |
Beta Was this translation helpful? Give feedback.
-
@lazyloader The CLR and bytecode verification process prevents modifications to readonly fields. See ECMA 335 II.16.1.2 Field contract attributes
|
Beta Was this translation helpful? Give feedback.
-
Rethink your constructors? A similar limitation is discussed here: #419. Bottom line: constructors should do the least amount of work, that is, member-wise initialization (and perhaps validation). Whenever you find yourself doing more, you should consider decoupling the requirements using some other mechanisms (like a factory method, etc). |
Beta Was this translation helpful? Give feedback.
-
I think this would need some sort of "ref delegate" or at the very least a "ref local method" to prevent it from escaping scope. Probably also a CLR change to allow writing to read-only fields from outside of a constructor. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
It has been pointed out by a few people on here already that it would be nice to have methods that can set readonly fields. This seems to defeat the point, so they often have some limitations:
However, those are already characteristics of local functions, so instead of allowing:
We should allow this:
This condenses the information and expresses the fact that nothing can use
InitA
orInitB
except for the constructor. It also takes up less lines and characters. I was surprised that this doesn't work, seeing as the local function is in the constructor, visually speaking, though I know it is compiled outside of it, however, I think it's intuitive to think it would work in this way.Beta Was this translation helpful? Give feedback.
All reactions