views:

247

answers:

11

Thus far, Microsoft's C# team has resisted adding formal compile-time macro capabilities to the language. There are aspects of programming with WPF that seem (to me, at least) to be creating some compelling use cases for macros.

Dependency properties, for instance. It would be so nice to just be able to do something like this:

[DependencyProperty]
public string Foo { get; set; }

and have the body of the Foo property and the static FooProperty property be generated automatically at compile time. Or, for another example an attribute like this:

[NotifyPropertyChanged]
public string Foo { get; set; }

that would make the currently-nonexistent preprocessor produce this:

private string _Foo;

public string Foo
{
   get { return _Foo; }
   set { _Foo = value; OnPropertyChanged("Foo"); }
}

You can implement change notification with PostSharp, and really, maybe PostSharp is a better answer to the question. I really don't know.

Assuming that you've thought about this more than I have, which if you've thought about it at all you probably have, what do you think? (This is clearly a community wiki question and I've marked it accordingly.)

+1  A: 

Have you looked at T4?

Hightechrider
I've seen it, but I sure don't understand it.
Robert Rossney
A: 

The things you are suggesting are now both easy to implement with dynamic objects in 4.0. I think C# is a big enough language, and I think that adding a preprocessor and some kind of fairly sophisticated macro system would make it way bigger, and I think it would deliver little value that couldn't be delivered equally well with little language tweaks and clever libraries.

Do you really want to retrace the footsteps of C++ in this area?

mquander
Not at all - I have no attachment to macros if there's another way of doing this. But it seems to me that dynamic objects are going almost exactly in the wrong direction from type-safe compile-time checking of property-change notification code. How would dynamic objects solve that problem?
Robert Rossney
Well, if the problem is "I want a non-dynamic, statically typed object with automatic property change calls in the properties," I guess it doesn't solve the problem. If the problem is just "I want automatic property change calls in the properties" then it seems to. In any case, my greater point is that it would be easier to add a feature like this to the language through little targeted tweaks than to add a whole macro system.
mquander
+3  A: 

For my part, I hope we don't see formal compile-time macros like this. The idea of using attributes (or other language syntax) to inform the compiler that it should rewrite code at compile time is not new and could probably be expanded to support additional scenarios like you describe.

This is not much different than tools like PostSharp, except that by having the compiler do the expansion it happens earlier and isn't actually rewriting the IL.

Scott Dorman
A: 

Personally I found myself wishing C# had C-style preprocessor macros from time to time. The last time was when I had to write a fill-like recursive algorithm to traverse a graph-like structure (think a* but not quite).

It wouldn't really put a strain on the compiler writing team since the compiler code would remain unaffected, all it would need is an extra preprocessor pass at the start. They can just reuse the MSVC preprocessor. It would mess with Intellisense perhaps, but then nobody expects perfect Intellisense when preprocessor macros are involved.

The biggest downside of macros in C++ wasn't the macros themselves, it was the header file mess that was C++'s only cross-file linking option. C# fixed this dated paradigm, so pure preprocessor macros (ie no #include or #pragma once) would only help.

Blindy
I quite agree. As long as you're not stuck with headers, preprocessing is a fine thing and can be pretty handy.
DeadMG
A: 
public string Foo { get; set; } 

Isn't that a compiler directive? I mean, who creates the backing property, the getter, and the setter.

Seems like you really just want more of this, for example:

public string Foo { get; setNotify("Foo"); } 
David B
+2  A: 

I understand the problem, but I think there are far more elegant solutions to it than preprocessor macros. C-style preprocessor macros have only limited power and are hard to maintain. (C++ templates were introduced to make them more powerful and easier to handle, but they had different problems.)

You might want to look at the boo language's extensible compiler pipeline: It allows you to create completely new keywords and syntax by writing classes that transform the compiler's AST before code is genereted. That way, things like LINQ queries, automatic properties or indexers can be added as modules to the existing language (after all, LINQ, automatic properties and friends are implemented as AST transformations in the C# compiler, too. You just can't add custom transformation steps with C#, because the compiler pipeline isn't open).

nikie
A: 

You can partially solve this problem without macros, but with a not-so-nice workaround (using generic static PropertyChangedEventArgs fields which are one-time initialized by reflection). The drawback is that you need to create different instances of the generic property class per property, which would be a lot easier with macros. Please have a look here: http://www.codeproject.com/KB/WPF/AutoPropertyChanged.aspx.

Alex
A: 

As Hightechrider says, you can use T4 to achieve quite a bit. For instance, I created a project, and added a new file called DepProp.tt. I then removed it's Custom Tool property, and placed the following code in it:

<#+
    void DependencyProperty(string name,Type type)
    {
        WriteLine("");
        WriteLine("private " + type.ToString() + " _" + name + ";");
        WriteLine(type.ToString() + " " + name);
        WriteLine("{");
        WriteLine("get");
        WriteLine("{");
        WriteLine("return _" + name + ";");
        WriteLine("}");
        WriteLine("set");
        WriteLine("{");
        WriteLine("_" + name + " = value;");
        WriteLine("//PropertyChanged()");
        WriteLine("}");
        WriteLine("}");
    }
#>

(Please note, I know this example doesn't actually implement a dependency property, I'm just showing what's doable).

I then created a C# class file, and put the following code in it:

//<#@ include file="DepProp.tt" #>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PlayAreaCS2008
{
    class Class2
    {
        //<# DependencyProperty("Num1",typeof(string)); #>
    }
}

Finally, I set this class files Build Action to None, and it's custom tool to TextTemplatingFileGenerator. The result? A generated file is created, and text templating kicks in and spits out the additional code I wanted. You continue to get syntax highlighting (but not full intellisense) in the Class file.

Damien_The_Unbeliever
T4 is powerful but it seems that no one knows about it.
emddudley
+1  A: 

PostSharp ist the best solution for this issue I know.

On a sidenote, I think that C# + PostSharp + EntLib + Unity + CodeContracts finally is what C# should have always been. Too sad that Microsoft don't seem to dislike boilerplate code enough.

There seems to be the idea that the VB 6.0 - victim is the most relevant user of their language, I can't explain their disregard of some of the more enterprisey topics in any other way.

Turing Complete
PostSharp is or isn't the best solution?
apollodude217
It is. However, it's outright scary that Microsoft didn't come up with it in the first place, they can't be THAT oblivious of the fact that they have amazing APIs but require unbelievable amounts of pointless boilerplate code (INotifyPropertyChanged - for example).
Turing Complete
A: 

I actually had a discussion with a colleague of mine of what I think would be the optimal solution to all AOP software development.

Every method that is not on a sealed class should raise events for method entry, method exit, and method error. This way you can easily apply AOP to any method by just hooking into that event. And then for these events to have EventArgs that expose the incoming parameters and return results to allow interception of these for inspection or mutation.

For classes that are sealed these events should just be bypassed entirely.

The reasoning behind this is if it was eligible to all methods period any registration scheme would be instantly trivial to bypass because all you need to do is intercept where it returns licensed = false and mutate that result to be true.

Chris Marisic
A: 

Funny - I was just saying the other day that the C# has been slowly implementing all the features the Boo language brought to .NET in 2004/2005. First it was type inference. Now the dynamic keyword and DynamicObject object concept. The last piece is macros. Maybe we'll start seeing DSLs in C# - though ALGOL-based languages like Boo/Python seem to be better for that.

mattmc3