-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Proposal: Property templates #10654
Comments
Those two proposals are essentially macro expanding/code generation On Mon, 18 Apr 2016 13:49 Robin Sue, notifications@github.com wrote:
|
If the suggestions around properties and expression bodies for get/set were implemented (eg see #7881 and #8364), then the code could be reduced to just one more line than your example, without any need to implement interfaces or having any magic code generation going on: public class Foo
{
private T PropertyChanged<T>(string name, T value)
{
Console.WriteLine($"{name} changed to value {value}");
return value;
}
public string Name { get; set => PropertyChanged(nameof(Name), value); }
public int Age { get; set => PropertyChanged(nameof(Age), value); }
} |
@DavidArno INPC is a simple case and an easy straw man to demolish. I hate writing dependency properties. It's a real drag and all the boilerplate obscures the code.
Now to get the above working with current dependency object technology the actual name of Property would have to be scoped correctly. If it got generated as AProperty, BProperty, and CProperty then the dep property name resolution would work. Note that the above is all statically typed. There is no requirement to decend into T4 template hell. I've written enough code generators to know that it is not fun. However I agree that the above is probably not general enough. It seems to me that my proposal looks like some kind of lexical scoping that allows composing classes out of smaller bits. The injected class bits can access the outer class via declared interfaces or classes. |
Though this link http://www.infoq.com/news/2016/04/CSharp-7 does seem to suggest that code generation will make it in with the "replace" keyword. Maybe I'm wrong. Sounds like macro expansion to me :) |
@bradphelan As others mentioned, #5292 and #5561 are the perfect fit for this scenario, public partial class Foo : DependencyObject {
public string Name { get; set; }
}
// to be generated
public partial class Foo {
public static readonly DependencyProperty NameProperty =
DependencyProperty.Register("Name", typeof(string), typeof(Foo));
replace public string Name {
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
} Also, this is currently planned for C# 7.0 (#2136). |
"perfect fit" might be going a little far. If one is prepared to turn all such classes into partial classes and implement a code generator that gets run as part of the build process, then it's a fit. Not sure that makes it "perfect" though, as it seems more like a hack to me at least. |
Yeah. I'm slowly coming around to it. Thanks for the rewrite of my example. What I don't see here.
is the intention in the hand written code that Name should be replaced and what pattern it should be replaced with. What if there was another property and I wanted a different pattern to be applied. Where do I go to look in the solution to navigate to the thing that generates this? Will the templates be applied by assigning attributes. eg.
|
@DavidArno: In my opinion, code generation is way to undervalued. There are lots of very useful things that you can do with code generation, and if Roslyn finally supports a nice way to integrate it into the build process, then great! A lot of feature/language design requests for C# and VB here in github can be tackled with code generation; if the problem and the code generator is generally applicable, there's nothing from stopping the Roslyn team to integrate it into the language proper. So I don't see code generation has a hack, in general. Especially since you don't want to build in (too much) framework-specific stuff into the language, such as dependency properties or |
@bradphelan That's totally up to you. The generator API provides syntax nodes for you to examine and this is nothing like macro expansions - I'm not 100% sure on the details though. I suggest you to read those proposals and ask if you had questions. @DavidArno I think writing generators are a one-time thing and I expect they will be available as NuGet packages for you to use. As for making classes |
@bradphelan You can read more about source generators in generators.md. The plan is to bring them in the same way Roslyn analyzers are brought in today. They simply take in a As for debugging and viewing generated source, I think the plan is to add a new node in the solution explorer, that would contain the generated source. This would allow you to step through and debug it with VS as well. |
Also, if you want to see source generators demoed, take a look at the "The Future of C#" talk from BUILD. The generators are demoed around 54mins. It's really cool stuff. |
@axel-habermaier Re "A lot of feature/language design requests for C# and VB can be tackled with code generation" Actually records or even ADTs can be simulated with generators until vnext. 😄 |
@alrz Which is exactly what one of the early prototypes of injectors did 😝 |
@alrz: Yes, indeed. I've recently begun to consider code generation whenever I see a new language feature proposal. It's amazing how much you can do without explicit language support if source generation is nicely integrated into the build process. It's true that real macro functions or code quotations ala F# would be nice, but I'm sure someone is going to build a nice library on top of what C# 7 is hopefully going to provide. |
I hadn't realised that the plan was to build code generators into Roslyn. In that case, I take back my "hack" comment. This really does open up so many possibilities. This means we can ship NuGet packages supporting records and discriminated unions (DU's) on the same day as C# 7 ships, rather than having to wait until v8 for those features. Suddenly, @alrz's request in #10153 for extension operators makes sense as a way of implementing DU's. I could have, eg: [Union]
partial struct SomeUnion
{
int IntValue { get; }
string StringValue { get; }
} which can be turned into a usable union. However, currently, the |
Just stumbled on this issue, after recently posting #10882. From the tone in here, I feel a little calmer that this source generator thingy actually will surface in a not to distant time. |
We are now taking language feature discussion in other repositories:
Features that are under active design or development, or which are "championed" by someone on the language design team, have already been moved either as issues or as checked-in design documents. For example, the proposal in this repo "Proposal: Partial interface implementation a.k.a. Traits" (issue 16139 and a few other issues that request the same thing) are now tracked by the language team at issue 52 in https://github.com/dotnet/csharplang/issues, and there is a draft spec at https://github.com/dotnet/csharplang/blob/master/proposals/default-interface-methods.md and further discussion at issue 288 in https://github.com/dotnet/csharplang/issues. Prototyping of the compiler portion of language features is still tracked here; see, for example, https://github.com/dotnet/roslyn/tree/features/DefaultInterfaceImplementation and issue 17952. In order to facilitate that transition, we have started closing language design discussions from the roslyn repo with a note briefly explaining why. When we are aware of an existing discussion for the feature already in the new repo, we are adding a link to that. But we're not adding new issues to the new repos for existing discussions in this repo that the language design team does not currently envision taking on. Our intent is to eventually close the language design issues in the Roslyn repo and encourage discussion in one of the new repos instead. Our intent is not to shut down discussion on language design - you can still continue discussion on the closed issues if you want - but rather we would like to encourage people to move discussion to where we are more likely to be paying attention (the new repo), or to abandon discussions that are no longer of interest to you. If you happen to notice that one of the closed issues has a relevant issue in the new repo, and we have not added a link to the new issue, we would appreciate you providing a link from the old to the new discussion. That way people who are still interested in the discussion can start paying attention to the new issue. Also, we'd welcome any ideas you might have on how we could better manage the transition. Comments and discussion about closing and/or moving issues should be directed to #18002. Comments and discussion about this issue can take place here or on an issue in the relevant repo. I am not moving this particular issue because I don't have confidence that the LDM would likely consider doing this in the form proposed. I would expect that, once (if/when) source generators become a language feature, there would be an add-on using that to handle these use cases. |
Extend the language to allow the creation of generic properties. A generic property is all the logic and storage that a single property on a class may require. It encourages reuse and DRY. It is not a general macro system but encapsulates the property pattern that is already well understood in C#.
One may define the following example class with all the noise we are used to expect.
We can DRY this up by the following process.
First define an interface for the type of object you wish to attach your properties to.
then at the same scope that classes are defined declare a generic property by introducing a keyword property to distinguish it from classes and namespaces. The property keyword would be parameterized by a type that constrains they type of classes that property can be attached to. The name of the property (in this case ReactiveProp) is also parameterized to specialize the code and storage requirements of the property.
The property would need to know it's own name so nameof(.) might be a good way to indicate that. Maybe another method would work better??.
Now create the class you want to attach your properties to. In this case there is the support method PropertyChanged exposed through the IReactive interface that all properties can access.
Now we can test our new class.
Output would be
This reduces the line count in the class from 17 lines to 7 lines which is a huge improvement.
This would require support from #850
The text was updated successfully, but these errors were encountered: