Getter and Setter delegates for Auto Properties

Topics: C# Language Design
Jul 1, 2014 at 7:22 PM
When building applications using WPF and Databinding very often we find that in order to implement INotifyPropertyChanged we implement standard properties with a private backing field rather than Auto Properties. This makes the code much more cluttered than it need be.

ie:
public class Foo
{
    private string m_stringProperty;

    public string StringProperty
    {
        get
        {
             return m_stringProperty;
         }
         set
         {
             m_stringProperty = value;
             PropertyChanged("StringProperty");
          }
    }
}
Since the compiler already generates the backing field and the accessor code from the specification
public string StringProperty { get; set; }
It would be low hanging fruit to implement a getter and setter notification callback syntax somewhat like this
public class Foo
{
    public string StringProperty 
    { 
         get( GetDelegate ); 
         set( SetDelegate ); 
    }

    // Called before value is returned from property getter
    private void GetDelegate(PropertyDelegateEvent e)
    {
        // Do something with the value.
     }

     // Called before value is set on the backing field
     private void SetDelegate(PropertyDelegateEvent e)
    {
        PropertyChanged(e.PropertyName);
     }

}
And the PropertyDelegateEvent has the following shape:
public class PropertyDelegateEvent<TProperty>
{
    public <TProperty> Value;
    public string PropertyName;
}
***** OR ****
public class Foo
{
    public string StringProperty { get; set; } : Notify
}
Where the compiler automatically calls the PropertyChanged Handler if the enclosing class has an Interface having a PropertyChanged method that takes a single string parameter.

***** AND/OR ****
public class Foo
{
    public string StringProperty { get; set; } : Notify( NotifyDelegate )
}
Where the compiler automatically calls the NotifyDelegate just prior to the setter returning.
Jul 12, 2014 at 10:38 AM
I think a nicer way to allow this would be something like metaprogramming. Which should be easier now with Roslyn.

Maybe something like this https://roslyn.codeplex.com/discussions/541131
Jul 14, 2014 at 6:17 PM
I can't think of any overly-dominant property pattern where the get does something other than read a field; the most dominant patterns I know of which would be uniform enough to benefit from a special syntax would be one were get behaves normally and set simply sets the field and calls a "refresh" method, or--for field types that support ==, compares the old and new field values and, if they differ, writes the field and call a "refresh" method. Perhaps allow auto-property-ish syntax for get if the set code is written as either on set { Refresh(); } if set { Refresh(); }?
Jul 16, 2014 at 12:58 PM
Just for the sake of completeness here's one I often encounter where the get does something non-trivial. Usually the setter is missing or trivial.
private List<Stuff> _list;
public List<Stuff> List
{
    get { return _list ?? (_list = new List<Stuff>()); }
    set { _list = value; }
}
We can do relatively short accessor bodies even today, e.g. the common INotifyPropertyChanged pattern:
private T _field;
public T Property
{
    get { return _field; }
    set { SetProperty(ref _field, value); }
}
// This may go to a base class which implements INotifyPropertyChanged
protected void SetProperty<T>(ref T field, T value, [CallerMemberName]string propertyName = null)
{
//...
}
Might worth a cautious thought to introduce a field symbol that represents the auto-implemented backing field analogous to value representing the implicit parameter for the setter. So the syntax would become:
public List<Stuff> List
{
    get { return field ?? (field = new List<Stuff>()); }
    set;
}
public T Property
{
    get;
    set { SetProperty(ref field, value); }
}
Saving the explicit field declaration and the trivial accessor body. The compiler would infer that an auto field of type T should be implemented if any of the accessors are trivial or references the field symbol. This is almost like GetDelegate/SetDelegate or a "refresh" method but allows an arbitrary body not just method calls.
However this can break existing code if another field symbol (most probably an existing member) is in scope. Unless the compiler emits a warning/error (which it doesn't do for value) this could silently change the original intended behavior. An option to solve this is to add an auto modifier to the property declaration (yay, another keyword :( ), just like async enables the use of await in the method body.
Aug 22, 2014 at 9:04 AM
Edited Aug 22, 2014 at 9:06 AM
One more thing to consider: if there is no explicit backing field declaration how would this feature work with the upcoming "Auto-property initializers" feature (assuming it is allowed in this case)? Would it invoke the setter or would it directly initialize the generated backing field? The former is pretty efficient and clean, however there might be cases where the latter is desirable e.g. subscribing to event handlers on the initial value in the setter. What do you think?
Aug 22, 2014 at 12:32 PM
I like your suggestions and I agree that it would be nice to be able to use the new language features to get rid of a lot of boilerplate code in WPF/Xaml applications.

pmont.
Aug 22, 2014 at 3:32 PM
If meta programming is too complicated, what about this idea just for properties:
public class Customer
{
    [AutoProperty]
    public Name { get; set; }

    [AutoPropertySetter]
    protected void SetProperty<T>(ref T field, T value, string propertyName)     
    {
        //implement your code here
    }

    [AutoPropertyGetter]
    protected T GetProperty<T>(ref T field, string propertyName)     
    {
        //implement your code here
    }
}
If the compiler will be able to recognize the pattern and call the generic methods most of the boilerplate will be gone. I think this method signatures support most of the reasonable variations.

By using AutoPropertyAttributte the developer will know some magic is going on.

If necessary, more than one variation could be created and identified by an attribute constant [AutoProperty("LazyCollection")].

The methods could be private, public or protected. So we can implement them in a base class (ViewModelBase).

The methods could also be virtual, to allow overrides, or have generic constraints to allow lazy instantiation.
Aug 22, 2014 at 4:17 PM
Anders has mentioned he's interested in exploring meta programming via attributes at some point. My guess is it would be similar to what PostSharp does but actually baking it into the language. I think if/when this gets added it will satisfy this need and many others.
Aug 22, 2014 at 8:41 PM
BachratyGergely wrote:
get { return _list ?? (_list = new List<Stuff>()); }
set { _list = value; }
That is an absolutely horrible pattern. Given the code:
var myList1 = new List();
thing.List = myList1;
var myList2 = thing.List;
var myList3 = thing.List;
myList1.Add("George");
myList2.Add("Larry");
myList3.Add("Ralph");
var myList4 = thing.List;
what should one expect myList1, myList2, myList3, and myList4 to contain?

Exposing mutable collections as properties is dangerous, even if the properties encapsulate them in read-only wrappers. If a type holds a non-wrapped collection which it will never modify, then having a property which return a new wrapper with each call might be reasonable, but otherwise collection contents should be extracted via methods.
Aug 23, 2014 at 1:08 PM
Edited Aug 23, 2014 at 1:10 PM
I think you misunderstand something. In your example all myList1, myList2, myList3, myList4 will refer to the very same object which contains all "George", "Larry", "Ralph". There is no new List created apart from the initial unless you explicitly set the property to null.
Besides you asked for a non-trivial getter, this lazy initialization is pretty common. It doesn't matter if there's a setter, or even if the property returns a collection type.
Oct 24, 2014 at 3:39 PM
BachratyGergely wrote:
I think you misunderstand something. In your example all myList1, myList2, myList3, myList4 will refer to the very same object which contains all "George", "Larry", "Ralph". There is no new List created apart from the initial unless you explicitly set the property to null.
Besides you asked for a non-trivial getter, this lazy initialization is pretty common. It doesn't matter if there's a setter, or even if the property returns a collection type.
My point was that just about the only time it makes sense to have a property of a mutable type is when the purpose of the property is to store the identify of an object which someone else owns or, in some rare cases, to hold the identity of a shared mutable object whose purpose is to create an association among other objects that hold references to it (e.g. something like an Object used for locking; even though Object has no mutable fields, it encapsulates various mutable aspects of lock state). In most cases where the latter pattern would be suitable, the setting of the locking object should be guarded in a CompareExchange; additionally, it may be necessary to have special code handle the situation where an object gets created but then not used, e.g.
if (_theLock == null)
{
  var newLock = new ReaderWriterLockSlim();
  Interlocked.CompareExchange(ref _theLock, newLock, null);
  if (_theLock != newLock)  // Someone beat us to writing _theLock, so newLock will be abandoned...
    newLock.Dispose();   // ... so if not Disposed here it never will be.
}
return _theLock;
If a particular property can safely be handled via simple code like:
if (_theThing == null)
  _theThing = new Thing();
return _theThing;
I'd rather see the code written out so as to make clear to any readers that no use of Interlocked is expected than have the code implicitly generated by the compiler.
Coordinator
Oct 25, 2014 at 11:16 PM
Olmo wrote:
public class Customer {
    [AutoProperty]  public Name { get; set; }
    [AutoPropertySetter] protected void SetProperty<T>(...)
    [AutoPropertyGetter] protected T GetProperty<T>(...)
}
If the compiler will be able to recognize the pattern and call the generic methods most of the boilerplate will be gone. I think this method signatures support most of the reasonable variations.
So that looks neat at first glance, but when I've tried to design further along these ideas I've never got past the brick walls:
  • How do you do it so you don't have to rewrite "AutoPropertyGetter/AutoPropertySetter" in every class? so that classes Customer, Order, Item, SKU, ... can all just re-use the same auto-getter and auto-setter?
  • How do tie things together so some of the autoprops in the class use one form of autogetter/autosetter while others of the autoprops use a different form and others don't use any at all?
  • How do you do it with just one backing field per property and zero additional storage?
  • How do you do it with no backing field at all per property, and zero additional storage per property, since the autosetter/autogetter just index into a dictionary? Think of XAML and how each object has 100s of dependency-properties where only the non-default properties take any storage.
I've made several attempts at this problem over the years since yes it would truly be a killer feature. I've spent time trying to persuade the VB/C# LDM that the feature would have value even if it didn't quite manage to solve all four problems. But I never persuaded anyone of this, not even myself. So I think it's a minbar to solve all four.

If you think your idea can be extended to solve these, or have other ideas on how to solve them, PLEASE fire away!
Oct 26, 2014 at 2:45 AM
lwischik wrote:
Olmo wrote:
public class Customer {
    [AutoProperty]  public Name { get; set; }
    [AutoPropertySetter] protected void SetProperty<T>(...)
    [AutoPropertyGetter] protected T GetProperty<T>(...)
}
If the compiler will be able to recognize the pattern and call the generic methods most of the boilerplate will be gone. I think this method signatures support most of the reasonable variations.
So that looks neat at first glance, but when I've tried to design further along these ideas I've never got past the brick walls:
  • How do you do it so you don't have to rewrite "AutoPropertyGetter/AutoPropertySetter" in every class? so that classes Customer, Order, Item, SKU, ... can all just re-use the same auto-getter and auto-setter?
Have auto-setter/getter proxies which implement some interface which defines the setter and getter methods, or one interface each for a getter and a setter?
public class DependencyPropertyAutoPropertyProxy : IAutoPropertyProxy {
    public TValue Getter<TParent, TValue>(TParent instance, string propertyName, TValue current) { }
    public void Setter<TParent, TValue>(TParent instance, string propertyName, ref TValue current, ref TValue proposed) { }
}

[AutoPropertyProxy(typeof(DependencyPropertyAutoPropertyProxy))]
public class Customer {
    [AutoProperty] public string Name { get; set; }
}
  • How do tie things together so some of the autoprops in the class use one form of autogetter/autosetter while others of the autoprops use a different form and others don't use any at all?
Have the AutoPropertyAttribute accept constructor arguments that can set to use a local implementation or a different proxy or to disable the meta-programming entirely?
[AutoPropertyProxy(typeof(DependencyPropertyAutoPropertyProxy))]
public class Customer {
    [AutoProperty] public string Name { get; set; }
    [AutoProperty(Proxy = typeof(SomeEnterprisyAutoPropertyProxy))] public Guid EntityId { get; set; }
    [AutoProperty(Enabled = false)] public string Name { get; set; }
}
  • How do you do it with just one backing field per property and zero additional storage?
I would think that an internal implementation would automatically work like this.
public class Customer {
    [AutoProperty] public string Name { get; set; }

    [AutoPropertyGetter] private T Getter<T>(string propertyName, T current) {
        return current;
    }

    [AutoPropertySetter] private void Setter<T>(string propertyName, ref T current, T proposed) {
        current = proposed;
    }
}
would translate into this:
public class Customer {
    private string _name;
    public string Name {
        get { return this.Getter<string>(nameof(this.Name), _name); }
        set { this.Setter<string>(nameof(this.Name), ref _name, value); }
    }

    private T Getter<T>(string propertyName, T current) {
        return current;
    }

    private void Setter<T>(string propertyName, ref T current, T proposed) {
        current = proposed;
    }
}
It gets a little trickier if you introduce the proxy mechanism mentioned above. You could instantiate it inline with the property and have it exist entirely transiently, or define a name in an attribute for a static method that would return a singleton instance.
public class Customer {
    private string _name;
    public string Name {
        get {
            IAutoPropertyProxy proxy = new DependencyPropertyAutoPropertyProxy();
            return proxy.Getter<Customer, string>(this, nameof(this.Name), _name);
        }
        set {
            IAutoPropertyProxy proxy = new DependencyPropertyAutoPropertyProxy();
            proxy.Setter<Customer, string>(this, nameof(this.Name), ref _name, value);
        }
    }
}
  • How do you do it with no backing field at all per property, and zero additional storage per property, since the autosetter/autogetter just index into a dictionary? Think of XAML and how each object has 100s of dependency-properties where only the non-default properties take any storage.
For inline autoproperty getters/setters you could support two signatures. One pair would accept the backing field value and the other wouldn't. The second version would require that the autoproperty getters/setters handle all of the logic for storage themselves and a backing property would never be created.
public class Customer {
    private Dictionary<string, object> dict = new Dictionary<string, object>();

    [AutoProperty] public string Name { get; set; }

    [AutoPropertyGetter] public T Getter<T>(string propertyName) {
        object value;
        if (dict.TryGetValue(propertyName, out value) && value is T) {
            return (T)value;
        }
        return default(T);
    }

    [AutoPropertySetter] public void Setter<T>(string propertyName, T proposed) {
        _dict[propertyName] = proposed;
    }
}
For the proxies you'd need a second interface which exposed the same convention.
public class DependencyPropertyAutoPropertyProxy : IAutoPropertyProxyWithNoBackingField {
    public TValue Getter<TParent, TValue>(TParent instance, string propertyName) { }
    public void Setter<TParent, TValue>(TParent instance, string propertyName, ref TValue proposed) { }
}
I've made several attempts at this problem over the years since yes it would truly be a killer feature. I've spent time trying to persuade the VB/C# LDM that the feature would have value even if it didn't quite manage to solve all four problems. But I never persuaded anyone of this, not even myself. So I think it's a minbar to solve all four.

If you think your idea can be extended to solve these, or have other ideas on how to solve them, PLEASE fire away!
This is a late night raw brain dump just focusing on the nature of the challenge. I don't doubt that it's loaded with warts and the exact code samples are just to serve as concepts. I find this problem interesting but honestly if we're going to step towards meta-programming I'd rather something more general purpose like AOP with official APIs to permit hooking into the compilation through attributes and to modify the AST of annotated classes. Then others can take a stab at these problems and let the ecosystem decide which handles the scenarios best.
Oct 26, 2014 at 10:45 AM
Edited Oct 26, 2014 at 11:44 AM
I mostly agree with all the solutions of Halo_Four but the IAutoPropertyProxy. I don't see any need to instantiate an object and do dynamic dispatch.

Instead, this new proposed solution gets a lot of benefits from relying on overload resolution and just static dispatch that can be inlined.

lwischik wrote:
Olmo wrote:
public class Customer {
    [AutoProperty]  public string Name { get; set; }
    [AutoPropertySetter] protected void SetProperty<T>(...)
    [AutoPropertyGetter] protected T GetProperty<T>(...)
}
If the compiler will be able to recognize the pattern and call the generic methods most of the boilerplate will be gone. I think this method signatures support most of the reasonable variations.
So that looks neat at first glance, but when I've tried to design further along these ideas I've never got past the brick walls:

> * How do you do it so you don't have to rewrite "AutoPropertyGetter/AutoPropertySetter" in every class? so that classes Customer, Order, Item, SKU, ... can all just re-use the same auto-getter and auto-setter?

Most of the cases, just by inheritance: You can declare the AutoPropertyGetter/AutoPropertySetter in the base class and then use it in the classes that inherit from it.
public class BaseEntity 
{
    protected T Get<T>(...)
    protected void Set<T>(...)
}

public class Customer : BaseEntity 
{
    [AutoProperty]  public string Name { get; set; }
}
In this new approach, the AutoPropertyGetter and AutoPropertySetter are not necessary anymore. Instead the convention methods Get and Set are used by default.

If you need POCO support, then nothing stops you from making the methods static and taking the instance as a parameter.
public static class EntityTools 
{
    public static T Get<T>(this object instance,...)
    public static void Set<T>(this object instance,...)
}

public class Customer 
{
    [AutoProperty(typeof(EntityTools))]  public string Name { get; set; }
}
The generate code will be something like:
public class Customer 
{  
    string name;
    public string Name 
    { 
       get { return EntityTools.Get(this, "Name", ref name); } 
       set {  EntityTools.Set(this, "Name", ref name, value); } 
    }
 }
Note that is just an static call that will probably be inlined.

Would be really nice to be able to inherit from AutoPropertyAttribute to simplify the pattern a little bit further:
public class AutoPropertyToolsAttribute : AutoPropertyAttribute
{
    public AutoPropertyToolsAttribute(): base(typeof(EntityTools))
}

public class Customer : BaseEntity 
{
    [AutoPropertyTools]  public Name { get; set; }
}

> * How do tie things together so some of the autoprops in the class use one form of autogetter/autosetter while others of the autoprops use a different form and others don't use any at all?

For the common cases it just depends on the property type, so I would use overload resolution. For example if there's a Set for string it will take precedence over a Set<T>. All the methods will probably be in-lined and no need for reflection.
public static class EntityTools 
{
    public static T Get<T>(this object instance, string propertyName, ref T field)
    public static void Set<T>(this object instance, string propertyName, ref T field, T value)

    public static string Get(this Entity instance, string propertyName, ref string field)
    public static void Set(this Entity instance, string propertyName, ref string field, string value)
}
For other variations, you can force the names of the methods.
public class BaseEntity
{
    protected T GetList<T>(string propertyName, ref List<T> field) 
    { 
        return field ?? (field = new List<T>());
    }

    protected void SetList<T>(string propertyName, ref List<T> field, List<T> value) 
    {  
       field = value ?? new List<T>(); 
    }
}

public class Customer : Entity
{
    [AutoProperty("GetList", "SetList")]  public List<string> Telephones { get; set; }
}
Again, being able to sub-class the attribute will allow to write AutoPropertyList that looks much better.

Because it relies in type inference and overload resolution, T can be the element type of the list, not the type of the property, and we can instantiate List<T> easily in the method.
public class Customer 
{  
    List<string> telephones;
    public List<string> Telephones 
    { 
       get { return EntityTools.GetList(this, "Name", ref name); } 
       set {  EntityTools.SetList(this, "Name", ref name, value); } 
    }
}
For using the standard behavior, just no AutoPropertyAttribute.

> * How do you do it with just one backing field per property and zero additional storage?

The previous examples explain that.

> * How do you do it with no backing field at all per property, and zero additional storage per property, since the autosetter/autogetter just index into a dictionary? Think of XAML and how each object has 100s of dependency-properties where only the non-default properties take any storage.

I will just add a AvoidBackingField parameter in AutoPropertyAttribute.
public class DependencyObject
{
    public T Get<T>(string propertyName, ref T field)
    public void Set<T>(string propertyName, ref T field, T value)
}

public class MyControl :  DependencyObject
{  
    public static DependencyProperty ColorProperty = 
        new DependencyProperty("TitleColor", typeof(Color), typeof(MyControl)); 
    [AutoProperty(AvoidBackingField = true)]public Color TitleColor { get; set; }
}
One more time, we could create a DependencyPropertyAttribute that inherits from AutoPropertyAttribute and sets AvoidBackingField=true.

Also, note that **the ref field stills there!**. It will be just a local variable declared in the getter and setter, so the generated code will be:
public class MyControl :  DependencyObject
{  
    public static DependencyProperty ColorProperty = 
        new DependencyProperty("TitleColor", typeof(Color), typeof(MyControl)); 
    public Color TitleColor 
    {  
       get { Get("TitleColor", ref Color rubbish); }  
       set { Set("TitleColor", ref Color rubbish, value); } 
    }   //R.I.P. declaration expressions? Snift snift....
}
The reason to keep the same signature with a faked field is to make type inference to work with minimal changes.

Of course you will need to declare the DependencyProperty static field by yourself. This is too WPF specific and requires additional metadata.

Also, in order to implement Get and Set in DependencyObject, the GetDependencyProperty method to get the static DependencyProperty from the PropertyName will be required, but this totally doable using reflection and some cache.
public class DependencyObject
{
    public T Get<T>(string propertyName, ref T field) 
    { 
         return (T)this.GetValue(GetDependencyProperty(propertyName));
    }
    public void Set<T>(string propertyName, ref T field, T value) 
    { 
        this.SetValue(GetDependencyProperty(propertyName), value);  
    }

    public DependencyProperty GetDependencyProperty(string propertyName)
    {
        //some cached reflection here
    }
}
I've made several attempts at this problem over the years since yes it would truly be a killer feature. I've spent time trying to persuade the VB/C# LDM that the feature would have value even if it didn't quite manage to solve all four problems. But I never persuaded anyone of this, not even myself. So I think it's a minbar to solve all four.

If you think your idea can be extended to solve these, or have other ideas on how to solve them, PLEASE fire away!
I think by relying in overload resolution this solution is simple, complete and fast. Waiting for the fire back :)

PD: No reason why this should work also for static properties and fields. For the shake of completeness.
PD2: Of course Meta programming with attributes will be much more general and powerful. But with a little bit of luck the syntax for the properties could be just the same.
Oct 26, 2014 at 11:24 AM
Thing I like about the "proxy" approach is that it allows the logic to be treated as a proper aspect. If your use-case is INotifyPropertyChanged or using dependency properties then you can just shim in an existing auto-property proxy that implements the logic for you and never have to concern yourself with writing that code. In theory those "proxies" would either be something shipped with the framework or available via NuGet. It also puts no responsibility on the individual types to form an inheritance hierarchy, although I do agree that using a base setter/getter would be useful.

Of course, again, with proper meta-programming/AOP support, you and I would be free to implement something like this as we saw fit and we could allow them to compete on the marketplace of ideas. :)
Oct 26, 2014 at 11:40 AM
Halo_Four wrote:
Thing I like about the "proxy" approach is that it allows the logic to be treated as a proper aspect. If your use-case is INotifyPropertyChanged or using dependency properties then you can just shim in an existing auto-property proxy that implements the logic for you and never have to concern yourself with writing that code. In theory those "proxies" would either be something shipped with the framework or available via NuGet. It also puts no responsibility on the individual types to form an inheritance hierarchy, although I do agree that using a base setter/getter would be useful.
The same is true using the static method approach, like EntityTools example. Instantiating a type and calling a dynamic method immediately afterwards does not provide any extra flexibility.
Of course, again, with proper meta-programming/AOP support, you and I would be free to implement something like this as we saw fit and we could allow them to compete on the marketplace of ideas. :)
I would love meta-programing, but I expect C# 7 main topic to be pattern matching. So meta-programming could come in C# 8 maybe? That's like 2020 or something. This solution is easy to implement and will alleviate on of the most pressing issues with a syntax that could be forward-compatible.
Oct 26, 2014 at 1:47 PM
Olmo wrote:
Halo_Four wrote:
Thing I like about the "proxy" approach is that it allows the logic to be treated as a proper aspect. If your use-case is INotifyPropertyChanged or using dependency properties then you can just shim in an existing auto-property proxy that implements the logic for you and never have to concern yourself with writing that code. In theory those "proxies" would either be something shipped with the framework or available via NuGet. It also puts no responsibility on the individual types to form an inheritance hierarchy, although I do agree that using a base setter/getter would be useful.
The same is true using the static method approach, like EntityTools example. Instantiating a type and calling a dynamic method immediately afterwards does not provide any extra flexibility.
That's true. The implementation isn't as important as the mechanism.

As for the mechanism for avoiding a backing field, why not just base that on the signature of the getter/setter methods? That way you don't have to be concerned about a mismatch or dealing with "rubbish" parameters. If none of this is driven by interfaces then the compiler can set the expectation by convention, sort of how it does with awaiters.
Of course, again, with proper meta-programming/AOP support, you and I would be free to implement something like this as we saw fit and we could allow them to compete on the marketplace of ideas. :)
I would love meta-programing, but I expect C# 7 main topic to be pattern matching. So meta-programming could come in C# 8 maybe? That's like 2020 or something. This solution is easy to implement and will alleviate on of the most pressing issues with a syntax that could be forward-compatible.
I'm sure that we can all agree that none of this is on the board for C# 6.0. It does seem like C# 7.0 is about pattern matching but I don't think that means that it can't also be about something else. Of course that depends on how much C# remains tied to the VS release cycle, which would put a time period of about 2 years on the development cycle. I don't think that AOP would be that big of a deal, definitely less intrusive syntactically than pattern matching. And while I agree that this might be simpler it is a step towards AOP and I think that alone would create the slippery-slope conversation that the concept isn't orthogonal enough, and it is technically meta-programming even if we're not going to open the entire can of worms.
Oct 26, 2014 at 2:30 PM
As for the mechanism for avoiding a backing field, why not just base that on the signature of the getter/setter methods? That way you don't have to be concerned about a mismatch or dealing with "rubbish" parameters. If none of this is driven by interfaces then the compiler can set the expectation by convention, sort of how it does with awaiters.
I just keep it to allow type inference. For example if we have the methods:
public class DependencyObject
{   
    protected T GetList<T>(string propertyName, ref List<T> field) 
    { 
        return field ?? (field = new List<T>());
    }

    protected void SetList<T>(string propertyName, ref List<T> field, List<T> value) 
    {  
       field = value ?? new List<T>(); 
    }
}
An then we write:
public class MyControl :  DependencyObject
{  
    public static DependencyProperty ColorsProperty = 
        new DependencyProperty("Colors", typeof(List<Colors>), typeof(MyControl)); 
    [AutoProperty("List")]public List<Colors> Colors { get; set; }
}
Will be converted to:
public class MyControl :  DependencyObject
{  
    public static DependencyProperty ColorProperty = 
        new DependencyProperty("Colors", typeof(List<Colors>), typeof(MyControl)); 
    public List<Colors> Colors 
    {  
       get { GetList("Colors", ref List<Colors> rubbish); }  
       set { SetList("Colors", ref List<Colors> rubbish, value); } 
    } 
}
And will be able to infer T === Color thanks to the rubbish variable. It set is just a generic method as I proposed in the initial solution you can not make concrete overloads for certain types and you'll need to create the list using reflection in some cases.

Also is nicer the the backing field depends on the property attribute (just one) than in attributes of the AutoSetter /AutoGetter that could be potentially contradictory. Thanks to sub-classing attributes the framework could provide a series of standard behaviors out of the box:
  • ViewModelPropertyAttribute: Doing the NotifyPropertyChange
  • LazyPropertyAttribute: Doing lazy instantiation with a backing field.
  • DependencyPropertyAttribute: As explained before.
  • LazyDependencyPropertyAttribute: The two before combined.
  • Build your own...
I think the solution looks quite sweet already, Is there any problem that I'm not aware?
Oct 26, 2014 at 3:21 PM
Edited Oct 26, 2014 at 3:24 PM
Halo_Four wrote:
Have auto-setter/getter proxies which implement some interface which defines the setter and getter methods, or one interface each for a getter and a setter?
public class DependencyPropertyAutoPropertyProxy : IAutoPropertyProxy {
    public TValue Getter<TParent, TValue>(TParent instance, string propertyName, TValue current) { }
    public void Setter<TParent, TValue>(TParent instance, string propertyName, ref TValue current, ref TValue proposed) { }
}

[AutoPropertyProxy(typeof(DependencyPropertyAutoPropertyProxy))]
public class Customer {
    [AutoProperty] public string Name { get; set; }
}
I see two problems here.

First, the design seems to be too ad hoc. For the presented use cases, we need an additional propertyName argument, which is useful only for NotifyPropertyChanged-like properties and useless for other property usages. Imagine that you implement auto-locking: each access to the backing field inside the property needs to be enclosed by lock (someInstanceSpecificLockTarget) { ... } -- for this we would need to pass a lock target into the proxy. How would the proposed interface handle this? I doubt there is a single interface covering all the needed cases.

Second, this approach seems to be unnecessary inefficient. You get an extra object per property and an extra virtual call per access, which is unlikely to be inlined by the optimizer. If switching to sweeter syntax with no different semantics brings a considerable performance penalty, what's the value of the feature?

Metaprogramming-based approach looks better, as it seems to address both problems.
Oct 26, 2014 at 3:32 PM
VladD wrote:
Halo_Four wrote:
Have auto-setter/getter proxies which implement some interface which defines the setter and getter methods, or one interface each for a getter and a setter?
public class DependencyPropertyAutoPropertyProxy : IAutoPropertyProxy {
    public TValue Getter<TParent, TValue>(TParent instance, string propertyName, TValue current) { }
    public void Setter<TParent, TValue>(TParent instance, string propertyName, ref TValue current, ref TValue proposed) { }
}

[AutoPropertyProxy(typeof(DependencyPropertyAutoPropertyProxy))]
public class Customer {
    [AutoProperty] public string Name { get; set; }
}
I see two problems here.

First, the design seems to be too ad hoc. For the presented use cases, we need an additional propertyName argument, which is useful only for NotifyPropertyChanged-like properties and useless for other property usages. Imagine that you implement auto-locking: each access to the backing field inside the property needs to be enclosed by lock (someInstanceSpecificLockTarget) { ... } -- for this we would need to pass a lock target into the proxy. How would the proposed interface interface handle this? I doubt there is a single interface covering all the needed cases.
My solution based in overload resolution is free from this problem, as long as someInstanceSpecificLockTarget depends only on the object instance, not the property itself.
Second, this approach seems to be unnecessary inefficient. You get an extra object per property and an extra virtual call per access, which is unlikely to be inlined by the optimizer. If switching to sweeter syntax with no different semantics brings a considerable performance penalty, what's the value of the feature?
Also no problem with the overload resolution. Is a non-virtual instance or static method that will be inlined most of the time. No instance creation necessary.
Metaprogramming-based approach looks better, as it seems to address both problems.
Meta-programming is much more powerful and much more complex. [AutoProperty] with overload resolution solves a big chunk of the problem, with a minimal amount of effort. No changes in the IDE are necessary for example.
Oct 26, 2014 at 3:45 PM
Edited Oct 26, 2014 at 4:04 PM
Olmo wrote:
My solution based in overload resolution is free from this problem, as long as someInstanceSpecificLockTarget depends only on the object instance, not the property itself.
Well, maybe I don't understand your solution properly. What should be the proposed syntax for the following old-style class?
class Test
{
    object _mutex = new object();

    double _length = 0;
    public double Length
    {
        get { lock (_mutex) { return _length; } }
        set { lock (_mutex) { _length = value; } }
    }

    TimeSpan _age = TimeSpan.Zero;
    public TimeSpan Age
    {
        get { lock (_mutex) { return _age; } }
        set { lock (_mutex) { _age = value; } }
    }
    // ...
}
And how will it be expanded by the compiler?

Edit: In particular, in your example compiler seems to need some baked-in knowledge that propertyName parameter's value should be the property name. How are we going to solve this in general?
Oct 26, 2014 at 4:18 PM
Edited Oct 26, 2014 at 4:25 PM
--del--
Oct 26, 2014 at 5:08 PM
Edited Oct 26, 2014 at 5:09 PM
VladD wrote:
Olmo wrote:
My solution based in overload resolution is free from this problem, as long as someInstanceSpecificLockTarget depends only on the object instance, not the property itself.
Well, maybe I don't understand your solution properly. What should be the proposed syntax for the following old-style class?
class Test
{
    object _mutex = new object();

    double _length = 0;
    public double Length
    {
        get { lock (_mutex) { return _length; } }
        set { lock (_mutex) { _length = value; } }
    }

    TimeSpan _age = TimeSpan.Zero;
    public TimeSpan Age
    {
        get { lock (_mutex) { return _age; } }
        set { lock (_mutex) { _age = value; } }
    }
    // ...
}
And how will it be expanded by the compiler?
Just create the Get/Set methods in the instance, together with the _mutex.
class Test
{
    [AutoProperty] public double Length { get; set; } = 0;
    [AutoProperty] public TimeSpan Age { get; set; } = TimeSpan.Zero;
    
    //Here on in a base class
    object _mutex = new object();
    protected T Get<T>(string propertyName, ref T field) 
    { 
        lock (_mutex) return field;
    }

    protected void Set<T>(string propertyName, ref T field, T value) 
    {  
        lock (_mutex) field = value;
    }
}
And will be translated to:
class Test
{    
    [CompilerGenerated]
    private double <Length>k__BackingField;
    public double Length
    {
        get { Get("Length", ref <Length>k__BackingField) ; } }
        set { Set("Length", ref <Length>k__BackingField, value); } }
    }
    
    [CompilerGenerated]
    TimeSpan <Age>k__BackingField;
    public TimeSpan Age
    {
        get { Get("Age", ref <Age>k__BackingField) ; } }
        set { Set("Age", ref <Age>k__BackingField, value); } }
    }
    
    //Here on in a base class
    object _mutex = new object();
    protected T Get<T>(string propertyName, ref T field) 
    { 
       lock (_mutex) return field;
    }

    protected void Set<T>(string propertyName, ref T field, T value) 
    {  
        lock (_mutex) field = value;
    }
}
Even more, you could make it more explicit like like this:
class Test
{
    [LockedProperty]public double Length { get; set;}
    [LockedProperty]public TimeSpan Age { get; set;}
    
    //Here on in a base class
    object _mutex = new object();
    protected T GetLock<T>(string propertyName, ref T field) 
    { 
        lock (_mutex) return field;
    }

    protected void SetLock<T>(string propertyName, ref T field, T value) 
    {  
        lock (_mutex) field = value;
    }
}

public class LockedPropertyAttribute : AutoPropertyAttribute 
{
    public LockedPropertyAttribute(): base("GetLock", "SetLock"){}
} 
With a very similar translation, that now just uses the SetLock and GetLock. This way you could mix locked and non-locked properties in the same class seamlessly.
Edit: In particular, in your example compiler seems to need some baked-in knowledge that propertyName parameter's value should be the property name. How are we going to solve this in general?
Not sure if I understand. Is a feature for properties and all properties have a PropertyName. Where's the lack of generality?

The name will be passed as a parameter whether you need it or not, but is just a reference to a constant string, no memory allocation needed.
Oct 26, 2014 at 6:21 PM
Edited Oct 26, 2014 at 6:23 PM
Olmo wrote:
Just create the Get/Set methods in the instance, together with the _mutex.
Well, this means that the code
 object _mutex = new object();
 protected T Get<T>(string propertyName, ref T field) { lock (_mutex) return field; }
 protected void Set<T>(string propertyName, ref T field, T value) { lock (_mutex) field = value; }
must be duplicated in every class (or at least base class) which wants to use locked properties, right?

Than we'll have a problem if we wanted to declare some lockable properties and some implementing INotifyPropertyChanged on the same class: how the compiler would know which implementation should it take? (And how can we define several Get methods at the same class?)

Another problem is that this pattern cannot be directly used to define WPF's DependencyPropertys: instead of usual backing field you need a static backing field, declared in quite a special, parametrizable way.
Even more, you could make it more explicit like like this:
class Test
{
    [LockedProperty]public double Length { get; set;}
    [LockedProperty]public TimeSpan Age { get; set;}
    
    //Here on in a base class
    object _mutex = new object();
    protected T GetLock<T>(string propertyName, ref T field) 
    { 
        lock (_mutex) return field;
    }

    protected void SetLock<T>(string propertyName, ref T field, T value) 
    {  
        lock (_mutex) field = value;
    }
}

public class LockedPropertyAttribute : AutoPropertyAttribute 
{
    public LockedPropertyAttribute(): base("GetLock", "SetLock"){}
} 
Well, how do you expect the LockedPropertyAttribute work? Should the compiler create LockedPropertyAttribute instance at compile-time (possibly executing the code inside and crashing), or it will be resolved at runtime, so the property getter/setter would need to use reflection to resolve string "GetLock" into method GetLock? This can be even more problematic if LockedPropertyAttribute is defined in some other assembly.
Edit: In particular, in your example compiler seems to need some baked-in knowledge that propertyName parameter's value should be the property name. How are we going to solve this in general?
Not sure if I understand. Is a feature for properties and all properties have a PropertyName. Where's the lack of generality?

The name will be passed as a parameter whether you need it or not, but is just a reference to a constant string, no memory allocation needed.
Well, you see, propertyName is needed to tame the very special case of INotifyPropertyChange. I expected that for some other usage patterns we'll need some other additional parameters. But in order for compiler to know what should be the values of these parameters, we need to fix their semantics during feature design. This doesn't seem to be possible.

Example: how would you declare this?
class Lazy
{
    [CompilerGenerated]
    private double <Length>k__BackingField;
    private bool <Length>k__Created = false;
    public double Length
    {
        get { GetLazy("Length", ref <Length>k__BackingField, () => 25.0, ref <Length>k__Created) ; } }
        set { SetLazy("Length", ref <Length>k__BackingField, value, ref <Length>k__Created); } }
    }

    //Here on in a base class
    protected T GetLazy<T>(string propertyName, ref T field, Func<T> creator, ref bool created) 
    { 
        if (!created) { field = creator(); created = true; }
        return field;
    }

    protected T SetLazy<T>(string propertyName, ref T field, ref bool created, T value) 
    { 
        field = value;
        created = true;
    }
}
Oct 26, 2014 at 7:16 PM
VladD wrote:
Olmo wrote:
Just create the Get/Set methods in the instance, together with the _mutex.
Well, this means that the code
 object _mutex = new object();
 protected T Get<T>(string propertyName, ref T field) { lock (_mutex) return field; }
 protected void Set<T>(string propertyName, ref T field, T value) { lock (_mutex) field = value; }
must be duplicated in every class (or at least base class) which wants to use locked properties, right?
In your example, I think a base class will be the best solution, but If you can not do that (already inheriting from another entity that is not lockeable...), at least you'll need to implement ILockableEntity that has a object _mutex and then do a static class like EntityTools that takes an ILockableEntity intance in the Get and Set methods.
Than we'll have a problem if we wanted to declare some lockable properties and some implementing INotifyPropertyChanged on the same class: how the compiler would know which implementation should it take? (And how can we define several Get methods at the same class?)
By using different attributes in the properties:
 class Test
{
    [LockedProperty]public double Length { get; set;}
    [ViewModelProperty]public TimeSpan Age { get; set;}   
}
Each attribute refers to different instance or static methods for getting and setting the property.
Another problem is that this pattern cannot be directly used to define WPF's DependencyPropertys: instead of usual backing field you need a static backing field, declared in quite a special, parametrizable way.
I think I've solved this in my example before by using AvoidBackingField. You still have to declare the backing field but is has special metadata on it. This is a concrete feature to save writing the get/set and optionally the backing field, not the general meta-programming solution that we're waiting for.
Even more, you could make it more explicit like like this:
class Test
{
    [LockedProperty]public double Length { get; set;}
    [LockedProperty]public TimeSpan Age { get; set;}
    
    //Here on in a base class
    object _mutex = new object();
    protected T GetLock<T>(string propertyName, ref T field) 
    { 
        lock (_mutex) return field;
    }

    protected void SetLock<T>(string propertyName, ref T field, T value) 
    {  
        lock (_mutex) field = value;
    }
}

public class LockedPropertyAttribute : AutoPropertyAttribute 
{
    public LockedPropertyAttribute(): base("GetLock", "SetLock"){}
} 
Well, how do you expect the LockedPropertyAttribute work? Should the compiler create LockedPropertyAttribute instance at compile-time (possibly executing the code inside and crashing), or it will be resolved at runtime, so the property getter/setter would need to use reflection to resolve string "GetLock" into method GetLock? This can be even more problematic if LockedPropertyAttribute is defined in some other assembly.
That's definitely an issue! :S

Attribute values are generated at compile-time and stored in assembly metadata, and there are examples of attributes values being resolved at compile time, like AttributeUsageAttribute, that change the compilation behavior depending on AttributeTargets flag, but the sub-classing and the call to the base constructor is executed at run-time.

In order to allow inheriting from AutoPropertyAttribute (and this is a must-have) the compiler will need to evaluate as a constant sub-expression the arguments of the base call. Is that doable lwischik?

At any rate, this problem will have to be solved for any meta-programming solution.
Edit: In particular, in your example compiler seems to need some baked-in knowledge that propertyName parameter's value should be the property name. How are we going to solve this in general?
Not sure if I understand. Is a feature for properties and all properties have a PropertyName. Where's the lack of generality?

The name will be passed as a parameter whether you need it or not, but is just a reference to a constant string, no memory allocation needed.
Well, you see, propertyName is needed to tame the very special case of INotifyPropertyChange. I expected that for some other usage patterns we'll need some other additional parameters. But in order for compiler to know what should be the values of these parameters, we need to fix their semantics during feature design. This doesn't seem to be possible.
PropertyName is also necessary for the case of DependencyProperty/store values in a dictionary, but I see your point.
Example: how would you declare this?
class Lazy
{
    [CompilerGenerated]
    private double <Length>k__BackingField;
    private bool <Length>k__Created = false;
    public double Length
    {
        get { GetLazy("Length", ref <Length>k__BackingField, () => 25.0, ref <Length>k__Created) ; } }
        set { SetLazy("Length", ref <Length>k__BackingField, value, ref <Length>k__Created); } }
    }

    //Here on in a base class
    protected T GetLazy<T>(string propertyName, ref T field, Func<T> creator, ref bool created) 
    { 
        if (!created) { field = creator(); created = true; }
        return field;
    }

    protected T SetLazy<T>(string propertyName, ref T field, ref bool created, T value) 
    { 
        field = value;
        created = true;
    }
}
It won't be possible to do that in the general case, but it will be possible for constant, just using the new ability to initialize auto properties.
class Test
{
    [AutoProperty]public double Length { get; set;} = 45;
}
Of course the value will be set at instantiate time, not in the first access, but this is not a big deal for constants.

Also there's a solution for complex objects, when a trivial new will be made, by using a new() constraint.
class Test
{
    [LazyProperty]public List<T> List { get; set;};

    protected T GetLazy<T>(string propertyName, ref T field) where T: new()
    { 
        return field ?? (field = new T());
    }

    protected void SetLazy<T>(string propertyName, ref T field, T value)  where T: new()
    {  
       field = value ?? new T(); 
    }
}
Also take into account that your pattern will create a delegate instance on every property access.

Of course is not as general as meta-programming, and I'll love meta-programming instead of this solution. But as a poor-man alternative solves most of the cases. And if meta-programming is based in attributes will be forward-compatible.
Oct 26, 2014 at 7:55 PM
Olmo wrote:
Another problem is that this pattern cannot be directly used to define WPF's DependencyPropertys: instead of usual backing field you need a static backing field, declared in quite a special, parametrizable way.
I think I've solved this in my example before by using AvoidBackingField. You still have to declare the backing field but is has special metadata on it. This is a concrete feature to save writing the get/set and optionally the backing field, not the general meta-programming solution that we're waiting for.
Well, my vision of this feature is that one can declare complete set-up for the property. A backing field is just one of the possible set-ups. For DependencyProperty it's a static backing field, for Lazy it's two backing fields. It might include an per-property event or whatever is syntactically possible right now. Not sure if this way is doable without metaprogramming, but it feels to be the right way.
class Lazy
{
    [CompilerGenerated]
    private double <Length>k__BackingField;
    private bool <Length>k__Created = false;
    public double Length
    {
        get { GetLazy("Length", ref <Length>k__BackingField, () => 25.0, ref <Length>k__Created) ; } }
        set { SetLazy("Length", ref <Length>k__BackingField, value, ref <Length>k__Created); } }
    }
[SNIP]
Also there's a solution for complex objects, when a trivial new will be made, by using a new() constraint.
class Test
{
    [LazyProperty]public List<T> List { get; set;};

    protected T GetLazy<T>(string propertyName, ref T field) where T: new()
    { 
        return field ?? (field = new T());
    }

    protected void SetLazy<T>(string propertyName, ref T field, T value)  where T: new()
    {  
       field = value ?? new T(); 
    }
}
Well, this would exclude the case when null is a valid value, so for the general case another backing field seems to be unavoidable.
Also take into account that your pattern will create a delegate instance on every property access.
I see. Actually, we need the third backing field to store the creator there.
Of course is not as general as meta-programming, and I'll love meta-programming instead of this solution. But as a poor-man alternative solves most of the cases. And if meta-programming is based in attributes will be forward-compatible.
In order to be compatible, we need to think about the metaprogramming solution's syntax. Any ideas, anyone?
Oct 27, 2014 at 1:17 PM
I'm sorry we can't also have a metaprogramming summit, but for anyone on this conversation that will be at the summit, it's a very high priority for me (again). Perhaps it would be helpful to have a different thread to identify questions since I think the simplest problem we'll ever address with metaprogramming is INotifyPropertyChanged - it is a poor archetype. There are at least two questions, both with nuances that can look like other questions - when does the metaprogramming occur and what are the artifacts and what is the metaprogramming syntax.

On the first, we are in a sufficiently rich world that there are probably multiple answers. For example - analyzers have different needs than code contracts than expansion generation than proxies different than IL AOP. There are a few driving factors - including what you debug in. Debugging has different demands if the coder is also the template writer and makes a lot of mistakes (think me) vs. a highly evolved pattern (think Gael/PostSharp). This impacts compiler extension points.

I've called metaprogrmaming syntax compiler attributes and public annotations. So, if anyone sees a distinction between those three phrases, please elaborate, and add any others. Java calls them "annotations" (thanks to Ted Neward for helping me grok what they do). Problem is that we call something else annotations in Roslyn - and after pushing to change that feature, I was convinced that it is perfect for what it is doing and this is totally different. My current term (the one in RoslynDom, CodeFirstMetadata/SourceFirstMetadata and ExpansionFirstTemplates) is PublicAnnotations. That's because it's vague- I've come to believe that it may be beneficial to have several syntaxes. My working syntax is (for C#) //[[ attributeLookingThingName(paramateres) ]]. This syntax, and any comment based syntax sucks if we don't give it a special color. But with special coloration it's nice. But I find some PublicAnnotations are really nice in regions (auto-collapse to find end) and I have prototypes with pseudo-attributes. That syntax comes from my belief that metaprogramming should have zero new intellectual surface area, because coders already have too much. And I remain deeply committed against using normal attributes, for reasons I can restate if I can remember them all.

I've also come to believe that the attributeLookingThingName is important and we are likely to want prefixes, but not too many prefixes. So, I don't want a naming collision with your things called "LoopOver." But from the programmer/user perspective, he's not committing to who loops over, just that someone should (this is even more evident in INotifyPropertyChanged). Thus I would really, really, really like to develop a group that helps herd the semantics on whatever we call these compiler communication thingees.

Another nice thing about an attribute looking syntax is that it allows targets. You don't question what I mean if I say

//[[nextLineOnly:OptionalOn(predicate)]]
//[[class:DuplicateForEach(list)]]

A nice thing about comments, is that we can build our own syntax inside of them :-). The scary thing about comments is that we can build 100 different syntaxes with 10,000 semantic variations :-(

If you are at the MVP summit, unless I screwed up, I'm doing a MVP2MVP that will focus on these big ideas (why I think we need a common language agnostic DOM of our source code, how I use it and how much time it saved). Unfortunately, because of a travel issue, I cannot be at the showcase. I follow that at DevIntersection where I will do a whole day on metaprogramming (where RoslynDom, etc will be only a small part). After that, I start breathing again, and am committed to writing a paper and/or video on my research.

I am so excited to be able to have these conversations!!!!
Kathleen
Oct 27, 2014 at 1:29 PM
Olmo,

My prototypes are very similar to what you propose. I found a few more twists and turns as I implemented, and I am implementing a harder problem (really good semantic logging).

My vision is a two part screen with the "simple" or "common" code on the left and the "real" or "full" code on the right (like TypeScript in split screen, but otherwise totally different). The translation between them is partially on templates that are inferred from patterns, occasionally on manual templates. Editing in the right changes the left (symbol name) or the template with confirmation (implementation change), or pulls that code out of the pattern and makes the left code explicit. There are a lot of little templates in that vision. It makes a great PowerPoint slide. There seems a lot of work on the way to that, and I am working on the formal understanding of the left "simple" code (Code/SourceFirstMetadata) and a new simpler template language that looks a bit like your vision (ExpansionFirstTemplates). And I believe that doing this directly against trees built for the compiler is a bit nuts and totally against our better selves. Thus, I built RoslynDom as a common language agnostic DOM for source code.

After over six months of nearly full time on this (thank my wonderful housemate), it is so great to be having this great discussion and was so great to see your vision so close to what I have working.

What's on GitHub right now is super not-ready. Two weeks, but I will try to have get synced with GitHub earlier.

Kathleen
Oct 27, 2014 at 8:50 PM
VladD wrote:
In order to be compatible, we need to think about the metaprogramming solution's syntax. Any ideas, anyone?
I will be really interested in discussing meta-programming further. A formal proposal in a Gist to get started will be wonderful.

We can also continue this conversation https://roslyn.codeplex.com/discussions/541131

But you have to admit that meta-programming could be seen as an alternative to almost any C# feature: LINQ, async/await, foreach, etc... and this solution for properties is not an exception.

Depending how good this theoretical meta-programming solution is (debugging experience / tooling / stack traces / etc...) creating new features like the one I proposed will be worth or not.

At any rate I think the solution covers gracefully the four requirements that lwischik asked for.
Oct 29, 2014 at 5:05 PM
The big differences between C# attributes and Java annotations being the retention and the ability to target individual statements? I wonder how difficult it would be to introduce that to C#.

Retention sounds like it should be easy. The attribute would exist in the AST expression and can be analyzed but would be discarded by the compiler before being emitted to the assembly.

More granular targeting would probably be more difficult. Perhaps it could be introduced as a mechanism of C# itself, where specially created attributes are permitted to target locals or statements. Those attributes would exist in the AST and could also be analyzed but they would have no retention and would be discarded by the compiler before being emitted to the assembly. Or they could be emitted as method-targeting attributes but require a property for an IL offset.

I know that this would require a number of modifications to at least C# and the compiler, if not the CLR proper, in order to support. I would just rather use a supported form of syntax such as attributes to be able to describe these kinds of declarations rather than inventing a new syntax, especially one buried in comments.
Oct 30, 2014 at 12:26 PM
Yes, these are two of the problems.

I struggle as much with floating information - information that belongs in the stream of statements or members, but is not attached to a specific member. Ay insertion (like an import) is one example.

I started out in the attributes camp and moved away from it, so I have to ask - what value do you see in using attributes?

Regardless, what we are talking about is an entirely new thing. It definitely need sot have structure, but ideally it could have an evolving or different structure - not just attributes, but JSON or XML for problems where they made sense.

Anyone at the summit will be able to see a quick fly-by of what I'm doing at the MVP 2 MVP Tuesday morning at 8AM.

And anyone that will be at my DevIntersection workshop will see it in depth.

I will write it up as soon as I catch my breath after DevIntersection, and will have the input from talking to people at the summit.
Oct 30, 2014 at 1:28 PM
KathleenDollard wrote:
Yes, these are two of the problems.

I struggle as much with floating information - information that belongs in the stream of statements or members, but is not attached to a specific member. Ay insertion (like an import) is one example.

I started out in the attributes camp and moved away from it, so I have to ask - what value do you see in using attributes?

Regardless, what we are talking about is an entirely new thing. It definitely need sot have structure, but ideally it could have an evolving or different structure - not just attributes, but JSON or XML for problems where they made sense.

Anyone at the summit will be able to see a quick fly-by of what I'm doing at the MVP 2 MVP Tuesday morning at 8AM.

And anyone that will be at my DevIntersection workshop will see it in depth.

I will write it up as soon as I catch my breath after DevIntersection, and will have the input from talking to people at the summit.
The value that I see in attributes is that they are already there, recognized and parsed by the compiler proper and handled as metadata in the CLR. They're not perfect but I'd rather start there and see what would need to be done to get them into range than to start with something completely new.

Granted, I'm thinking of this from within the possibilities of Roslyn development down the line, not as an outsider forced to live with the limitations of the compiler. With what Roslyn offers us right here and right now comments do make sense since they carry no retention, are embedded as trivia in the AST expression and impose no limitations on syntax, but I think that they're also dangerous in that they present a completely blank slate.

Assume that what I mentioned above could actually happen. AttributeUsageAttribute was extended to have another member to declare retention and AttributeTargets was extended to include a new enum member for individual statements. However the compiler or CLR implemented that aside what other limitations do you see with attributes that would create blockers for meta-programming scenarios?