Proposal: Add the ability to execute arbitrary code in instance initializers #8798
Replies: 33 comments
-
An alternative syntax could be something like this which doesn't use the
However, I think using |
Beta Was this translation helpful? Give feedback.
-
Having FontSize = 72,
Text = "Hello",
.SetValue( Canvas.LeftProperty, 109),
.SetValue( Canvas.TopProperty, 109),
}; |
Beta Was this translation helpful? Give feedback.
-
@CyrusNajmabadi in this proposal, the I did see another proposal to allow more generous fluent style programming that looks similar to the syntax you just provided. I wasn't a huge fan of that proposal though, as it involved many logical conundrums. |
Beta Was this translation helpful? Give feedback.
-
@CyrusNajmabadi the goal of this proposal is to allow arbitrary code to be executed in the initializer block -- not just call methods on the instance being initialized. The goal would be to allow doing anything a normal code block would be able to do -- like declare scoped variables, have multiple statement logic, loops, etc. |
Beta Was this translation helpful? Give feedback.
-
Riht. That's my point. up till now 'this' has never changed meaning. that's actually been something very intentional (i.e. inside a lambda, it's a lexical capture, unlike how JS works). It would def likely be too much of a stretch as i don't think it would be palatable at all to change that now.
The main issue is that you've now changed how |
Beta Was this translation helpful? Give feedback.
-
nodding along with @CyrusNajmabadi ... "this" (sorry 😅) is a nifty proposal, but a new keyword should (read: MUST 😁) be considered. @VincentH-Net, you might dig this (check out his cool project that dances around this problem space here). |
Beta Was this translation helpful? Give feedback.
-
Why not just: var textblock = new TextBlock
{
Width = 172,
Height = 80,
TextWrapping = TextWrapping.Wrap,
Foreground = Brushes.Orange,
FontFamily = new FontFamily( @"Baskerville Old Face" ),
FontSize = 72,
Text = "Hello",
SetValue( Canvas.LeftProperty, 109);
SetValue( Canvas.TopProperty, 109);
}; ? |
Beta Was this translation helpful? Give feedback.
-
@CyrusNajmabadi and @mike-eee I'm not too interested in debating the semantic point, as that is a secondary concern. I'm fine with a new keyword or the delegate style syntax or However, even if this is is just bikeshedding, I don't see the proposed syntax as changing the critical expectations around What's unique about my preferred syntax is giving C# authors the ability to write arbitrary code blocks as if they were declared on the type being referred to. I'll give you that. That's certainly never been done before in C#. Previously, As I said I am not opposed to a new keyword in place of |
Beta Was this translation helpful? Give feedback.
-
@YairHalberstadt I would not mind one bit if that was also supported. I would like the ability to put a code block in the initializer though, which was what the original proposal was mostly about -- even if the example I picked was a bit simplistic. |
Beta Was this translation helpful? Give feedback.
-
Literally for 20 years ...
Text = this.Foo;
this.SetValue( Canvas.LeftProperty, 109),
}; Two usages of |
Beta Was this translation helpful? Give feedback.
-
@CyrusNajmabadi thanks. that helps highlight the potential issues with using I am going to edit the original proposal to remove use of |
Beta Was this translation helpful? Give feedback.
-
Okay. I edited the proposal and included @YairHalberstadt's suggestion. |
Beta Was this translation helpful? Give feedback.
-
Why not: var textblock = new TextBlock
{
Width = 172,
Height = 80,
TextWrapping = TextWrapping.Wrap,
Foreground = Brushes.Orange,
FontFamily = new FontFamily( @"Baskerville Old Face" ),
FontSize = 72,
Text = "Hello",
{
SetValue( Canvas.LeftProperty, 109);
SetValue( Canvas.TopProperty, 109);
}
}; ? |
Beta Was this translation helpful? Give feedback.
-
I totally missed @CyrusNajmabadi's suggestion, but I think this is the right way to go:
Or maybe something unique/different/new:
Anyways, if this is what we're nitting about, then this proposal has a lot going for it, yes? :) |
Beta Was this translation helpful? Give feedback.
-
Essentially let's break this up into two orthogonal proposals:
|
Beta Was this translation helpful? Give feedback.
-
@YairHalberstadt I am thinking about it from an indexing listing of the available symbols at a particular location. Pressing For me at least, the |
Beta Was this translation helpful? Give feedback.
-
Intellisense already does this for object initialisers and properties. I don't see why method should be different. |
Beta Was this translation helpful? Give feedback.
-
Yeah good point @YairHalberstadt ... my creativity got the better part of me. 😆 |
Beta Was this translation helpful? Give feedback.
-
@YairHalberstadt I would be fine with no keyword required at all. That's certainly very economical. I just wonder if the type being initialized has a method with the same name as static a method in the outer scope, it might be confusing for both the reader and the compiler which method is being referred to. For example:
|
Beta Was this translation helpful? Give feedback.
-
That's why i'm proposing that you do: Note: this is basically exactly what VB does with |
Beta Was this translation helpful? Give feedback.
-
If #1449 gets approved, it may be good to include this proposal in the syntax for that feature since it looks very similar to the initializer syntax. Although, it might have less utility in that context.... Since #1449 doesn't exist, I haven't really felt and cannot predict whether this capability would be sorely missed if it weren't included in #1449. |
Beta Was this translation helpful? Give feedback.
-
There's also some potential overlap/symmetry with #803, #2355, #1879, #1534, etc. |
Beta Was this translation helpful? Give feedback.
-
This is the bit I'm really struggling with. What you are proposing encourages private TextBlock SomeMethod()
{
return new TextBlock
{
Width = 172,
Height = 80,
TextWrapping = TextWrapping.Wrap,
Foreground = Brushes.Orange,
FontFamily = new FontFamily(@"Baskerville Old Face"),
FontSize = 72,
Text = "Hello"
}
.SetValue(Canvas.LeftProperty, 109)
.SetValue(Canvas.TopProperty, 109);
} I see no positive benefit to this proposal unfortunately. So it's a 👎 from me. |
Beta Was this translation helpful? Give feedback.
-
First, IF a fluent API already exists, then this new syntax doesn't add value. You are correct. However, fluent APIs in many cases do not and will not ever exist - or at least, the old APIs cannot be made fluent because it would be a breaking change to the current method signatures. Second, your criticism/concern only applies to the single statement portion of the proposal. The proposal also includes a syntax for multi-line scoped code blocks. If you need those in some case, those currently break fluent syntax no matter what. So what I'm asking for is a more powerful initialization syntax that will (a) provide many of the benefits of fluent style APIs which will also work with any API, and (b) will be able to do things that fluent style APIs cannot do. |
Beta Was this translation helpful? Give feedback.
-
@DavidArno TLDR: that code sample you provided won't compile precisely because the Over here (#1614 (comment)) I showed a code sample for adding a fluent API wrapper using extension methods. However, that is quite cumbersome to do for every case. Moreover, there's still the code block use case.... |
Beta Was this translation helpful? Give feedback.
-
This also seems like it could be solved by providing an Action or such to the type which needs it, e.g. an |
Beta Was this translation helpful? Give feedback.
-
One of the express goals of the proposal was to eliminate the need to use extension method hacks to achieve inline initialization. Moreover, those delegate calls may not get inlined. Using explicit static methods (whether local or not), which would have a higher likelihood of being inlined, is even more painful than using delegates. |
Beta Was this translation helpful? Give feedback.
-
@juliusfriedman I certainly wouldn't want to have any such automagic initializer syntax - init logic is almost always contextual. |
Beta Was this translation helpful? Give feedback.
-
#2580 similar proposal |
Beta Was this translation helpful? Give feedback.
-
Also plesae include event initilization. return new TextBlock
{
Width = 172,
Height = 80,
TextWrapping = TextWrapping.Wrap,
Foreground = Brushes.Orange,
FontFamily = new FontFamily(@"Baskerville Old Face"),
FontSize = 72,
Text = "Hello",
OnTextChanged += (sender, arg) => {
Console.WriteLine("Text Changed");
}
} |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Let me know if something like this has already been proposed or discussed. I saw #1243 but it isn't the same.
Background
Currently we have to write initialization logic like this:
Any logic that isn't explicitly a property setter, must be done as actual code following the initializer. There are often many things that need to be initialized that are not properties. So we end up having to write a lot of follow up lines of code referencing the instance being initialized by variable name.
While the proposed syntax would have an economical advantage of saving keystrokes, it would also have an advantage of reducing opportunities for programming errors and also allow the compiler and language tools to infer more information about the programmer's intent regarding initialization logic.
That extra captured intent could help create some specific, useful code analyzers, etc.
Proposal
Amend the C# compiler to support this syntax (or something like it) -- and I'm using a made-up keyword
foo
in place of some as of yet undecided keyword -- for declaring arbitrary inline multi-statement initialization code blocks:It should also support this single statement syntax suggested by @YairHalberstadt:
The multi-line code block syntax could be achieved using a delegate style if a new keyboard doesn't seem like a good idea:
Benefits
I mentioned some of these already in the background section, but here they are again:
Implementation
The code from the Proposal section should be rendered by the compiler into expanded C# to exactly match the code in the Background section. That means the compiled code should be fully backwards compatible.
In other words, I believe this can be implemented as a compiler only change and not have any implications for the CLR, etc.
Beta Was this translation helpful? Give feedback.
All reactions