Closed ig-sinicyn closed 8 years ago
I think it should be easier to express code, rather than building the node syntax tree. The compiler itself could be used, to help (see #174)
@AdamSpeight2008 Well, I'm not sure that macros addition is the right way to go.
As for me it is too big and controversial feature to be easily fitted into c#. Also, the main benefit from macros - no need to construct code tree manually - is perfectly covered by
var stubCode = SyntaxFactory.ParseExpression(@"
public StubType StubProperty
{
get { return stubField; }
set
{
stubField = value;
OnPropertyChanged(StubPropertyName);
}
}")
All you have to do is replace stubs with actual nodes. And if you're too lazy, it can done using string interpolation,
var stubCode = SyntaxFactory.ParseExpression(@$"
public {typeName} {propertyName}
{
get { return {fieldName}; }
set
{
{fieldName} = value;
OnPropertyChanged({propertyName});
}
}")
thats all. If there're more real benefits from macro approach I'd be glad to hear it.
Now, here is what's wrong with macros:
nameof
operator. "Simpiler" params IEnumerable
and digit_separapors were not implemented at all.
Yes, designing a new language feature is hard. Despite all efforts there always be some corner cases where proposed design will not fit. Imagine now that you had to support the code filled with all bad-designed features you may wish. What, "no one will do that" again?
Well, why then spend time on feature the majority will not be able to use the right way?As a summary: code rewriters offer almost ideal balance between developer qualification, scenarios supported and cost of support. As for me there's no place for macros-driven metaprogramming in c#. However I would love to hear if I'm wrong.
I would like to upvote this proposal, seems like a natural addition to Roslyn and could allow a broader set of feature without chenging the language itself. There are a tons of possible use cases, perf improvement of serialization and aop just to name a few
@ig-sinicyn wrote: Also, the main benefit from macros - no need to construct code tree manually - is perfectly covered by
var stubCode = SyntaxFactory.ParseExpression(@" public StubType StubProperty { get { return stubField; } set { stubField = value; OnPropertyChanged(StubPropertyName); } }")
All you have to do is replace stubs with actual nodes. And if you're too lazy, it can done using string interpolation,
You're right you can do it using a string, then converting it at runtime. In which lies an issue, you don't get compile-time type-checking of that section of code. My proposal / idea is to have compile-time checked templates. (like C++)
@AdamSpeight2008 Emm... I'm not talking about runtime:)
SyntaxFactory.ParseExpression()
is common shortcut to get correct syntax three without doing something like this. After you've got valid AST it's relatively easy to replace with it the code you need to rewrite. Here's a roslyn code fix sample using the same approach.
So, the code above is meant to be executed at compile time as additional compilation step. No runtime magic at all.
If you want to prove that rewriter/macro is working correctly you had to write tests anyway. There always are some errors that cannot be caught by compiler.
@ig-sinicyn The example from the first link, would look something like this use a template function.
template syntaxnode FormWithTicker( string ns , string fn )
{
namespace %{ns}%
{
public class %{fn}%() : System.Windows.Forms.Form
{
public System.Windows.Forms.Timer Ticker
{
get; set;
}
[STAThread]
public void Main
{
}
}
}
The compiler would / should check at compile-time that the structure of the code is correct.
Well, from my point of view it is useless to check template itself.
As example, template code can derive from type not referenced by the template library. It could be derived from another template. It could use mixin-style template combinations. Or use members from type being passed as template argument. And so on and so on.
So, the only way to check template is to apply it to the real code. And at this moment there will be no difference between macros, code template and classical code rewriter.
Also, did you notice that your template could be easily replaced with usual base class? Having multiple ways to do something usually means that there's something wrong with language design. One more point for code rewriters:)
It seems that the discussion begins to look like "macro vs aop" holywar, so I'll stop for mow. Thanks, and let's wait for comments from someone from roslyn team:)
I've written a working implementation of Roslyn compiler plugins similar to this, along with attribute macros as described. Take a look at #3248.
In progress in #5561.
Hi!
The metaprogramming feature was discussed multiple times already (e.g. #98 and #2136) but all of discussions as so far ended with "too big to fit" resolution.
At the same time there are a lot of real-world codegen tasks, such as
Each of these uses its own code generation approach, but all of them work fine, nothing fails and no one hurts. So, lets start with assumption that adding one more way to apply some build-time-magic will not break anything.
Now, there are a lot of issues not related to the c# syntax and too specific to be supported directly by the c# compiler. To name a few: #1677 (support for INPC), dependency properties, #105 (easy Equals() implementation) and so on. It seems that allowing to add custom code rewriters is the only solution that can be safely done at c# side.
All of these issues perfectly fits into following restrictions:
for
if you do not like standard one" approach, no template-based magic to imitate algebraic types, no need for metalanguage and so on. Just write the code that automates writing some more code for you, thats all.In summary:
So, what I've missed?:)