Skip to content
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

Extension properties for classes #112

Closed
aarku opened this issue Jan 28, 2015 · 33 comments
Closed

Extension properties for classes #112

aarku opened this issue Jan 28, 2015 · 33 comments

Comments

@aarku
Copy link

@aarku aarku commented Jan 28, 2015

Extension methods were added for LINQ in C# 3.0, but I commonly run into cases where extension properties would be useful. Eric Luppert, who used to be on the C# team at Microsoft, wrote that extension properties were not implemented because other features were deemed more valuable. I think it is time to look at that decision again.

@sharwell
Copy link
Member

@sharwell sharwell commented Jan 28, 2015

I heard someone a few months ago mention the concept of "extension everything" when I brought up properties. If I'm not mistaken, the two most requested items which cannot be extended are:

  1. Properties
  2. Static members of a type

If static extension members were available, it would be possible for someone to (for example) provide an extension member Task.Delay for .NET 4.0 rather than putting it into TaskEx.Delay.

@ErikSchierboom
Copy link

@ErikSchierboom ErikSchierboom commented Jan 28, 2015

Ooh, static extension members! I'd like that. It would allow me e.g. extend the Assert class in xUnit.

@sharwell
Copy link
Member

@sharwell sharwell commented Jan 28, 2015

Even extension fields (for a reference type) would be possible by implementing them as the following:

If extension field FieldType f is added to type T:

private static readonly ConditionalWeakTable<T, StrongBox<FieldType>> _extensionField_f;

public static FieldType get_f(T obj)
{
    StrongBox<FieldType> box;
    if (!_extensionField_f.TryGetValue(obj, out box))
        return default(FieldType);

    return box.Value;
}

public static void set_f(T obj, FieldType value)
{
    StrongBox<FieldType> box = _extensionField_f.GetOrCreateValue(obj);
    box.Value = value;
}

@sharwell
Copy link
Member

@sharwell sharwell commented Jan 28, 2015

@ErikSchierboom that is an awesome example of a use case.

@kepeter
Copy link

@kepeter kepeter commented Jan 28, 2015

For me too it would be a very useful feature...
In most cases inherit a class makes it too complicated when I only need some properties computed from existing ones...
The last sample I remember is adding to the Color class capabilities of CMYK and HSV beside RGB and HSL...
The current options are more complicated than just extend the class with new properties...

@ashmind
Copy link
Contributor

@ashmind ashmind commented Mar 4, 2015

@sharwell just found this, but btw I've created #996 today specifically for static extension methods.

@ErikSchierboom A bit of an offtopic, but a weird thought: third-party libraries such as xUnit could adjust their API, allowing something like this. I don't expect BCL to do anything like that though, so static extension methods is still a better choice.

@chrisaut
Copy link

@chrisaut chrisaut commented Mar 4, 2015

@ashmind is right, we should think about this in a wider context. I think the only way to do so is to not cling to the existing syntax for extension methods (but of course keep it functional for methods for legacy support).

What about something like this:

public class MyClass { // we want to extend this
    public int One { get; } = 1;
}

// new keyword extension for class
// for all intents and purposes this is a static class
public extension class MyClassExtensions : MyClass { // we don't inherit, for extension classes this means what we extend
    // instance extension method
    public int M() => return this.One; // no need to declare a this MyClass instance argument, compiler will automatically bind "this"

    // instance extension property
    public int P => this.M(); // via "this", one can access both extension and non extension members

      // we can even do fields
    private int someField; // this would get hoisted into some ConditionalWeakTable<MyClass, SomeGeneratedStructWithFeldValues>
      // some "generatedstruct" would hold all fields for each "extension class"
    public int P1 {
        get { return someField; }
        set { someField = value; }
    }

    // instance event
    public event Action MyEvent; // underlying field against hoisted to ConditionalWeakTable

    // static extension method
    public static int SM() => return 42;

    // static extension property
    public static int SP => return 42;

    private static int someField; // this would get hoisted into some ConditionalWeakTable<Type, SomeGeneratedStructWithFeldValues>
    public static int SP1 {
        get { return someField; }
        set { someField = value; }
    }
} 

Something like this would solve all these extension requests.

@ErikSchierboom
Copy link

@ErikSchierboom ErikSchierboom commented Mar 4, 2015

@ashmind Interesting design, although I do hope static extension methods will get integrated.

@HellBrick
Copy link

@HellBrick HellBrick commented Mar 4, 2015

@chrisaut that's an interesting syntax. However, I think those 'extensions fields' may be pushing it too far: attaching state to another class in this way along with behavior just doesn't feel right or intuitive.

Having said that, I kind of like the idea of marking class as an extension container for a specific target class and thus avoiding writing this or the class name in every method or property declaration.

@chrisaut
Copy link

@chrisaut chrisaut commented Mar 4, 2015

Sure, I agree it's kinda weird. But otherwise you can't do property setters or events. Well I guess properties could write store their value somewhere else. But events? I don't know of a good scenario for either of those, but why limit it?

My main point was that it would feel natural to declare and use these when a dedicated extension class is introduced.

@HellBrick
Copy link

@HellBrick HellBrick commented Mar 4, 2015

it would feel natural to declare and use these when a dedicated extension class is introduced

It may appear natural to try that, but I'm afraid that's a feature that can easily be abused. If you want to attach an additional state to an instance of a class, I think in majority of cases it would be much better to either derive from it or to create a wrapper around it. Either way, you are explicit about your intentions. Using some automagical attached weak field references with an unclear lifetime as an alternative approach to design classes may have some appeal as a very cheap solution, but at the same time has a potential to lead to a bunch of the convoluted code that's gonna be difficult to maintain.

I know this may sound paranoid, because in reality everything can be misused and abused. But what are the real use cases for the extension fields? Extension properties can make a lot of sense if their getters and setters just call some members of the extended class, but those are okay and don't need the backing extensions fields. The idea of extension events sounds weird; I encountered one case where they might have come in handy - providing a way to subscribe to an internal event of an internal type via reflection - but the point was once again to use the state of the extended object, not to add an additional state.

And finally, if the language gets extension properties with explicit getters and setters and extension events with explicit add and remove methods, then the statefull extensions will be possible to implement manually in those (probably) rare cases when they actually make sense.

@sgjsakura
Copy link

@sgjsakura sgjsakura commented Mar 5, 2015

The language design for extension properties may simple using indexes, just like:

public static class MyClassExtensions
{
 public static int Data[this MyClass obj]
 {
   get { return 0; }
   set { return; }
 }
}
var data = myObj.Data;
myObj.Data = 1;

If there's more than one parameters in the indexer, this will raise and extension indexer property like

public static class MyClassExtensions
{
 public static int GetData[this MyClass obj, int index]
 {
   get { return 0; }
   set { return; }
 }
}
var data = myObj[0];
myObj[0] = 0;

The extension properity is just a code-sugar for shorten writting. User may use a Dictionary other way to store the property value, or just provide a computed property. But anyway The background-field store and all the other things is not the bussiness for this feature itself.

@chrisaut
Copy link

@chrisaut chrisaut commented Mar 5, 2015

I'm not saying it's a good idea to attach state to an object.

But, doing just that is a "natural" requirement/expectation if you want extension properties (and events)..

Otherwise you cannot do auto-properties (compiler needs to emit a backing field), which may make the feature feel incomplete again.

Even if that were disallowed, if you still allow property setters, developers will try to come up with their own solution and half of them will get it wrong in subtle ways. For instance they may create a Dictonary<MyClass, string> and store it there. Ooops, now the instance can never be garbage collected and you created a nice leak. Most developers don't even know about weak references or ConditionalWeakTable.

So if we really want to discourage attaching additional state (essentially we don't want extension fields), then I feel the only way is to explicitly only allow Property Getters, and not support Setters or even getter only auto properties.

Which may be fine. But my guess is people will bump into this limitation. I'm not sure if getters only would cover all of the scenarios people want. Or if we just say it covers enough of the scenarios and the rest is not worth it.

Maybe I overlooked some, but I only saw one usage scenario mentioned in this thread. Should we try to collect more to better gauge what people actually want from this?

@natalie-perret-1986
Copy link

@natalie-perret-1986 natalie-perret-1986 commented Apr 23, 2015

I would like to see that one finally implemented in C#7, that's pretty a long time that I'm waiting for such a feature in the language.
We would finally tend, somehow, to have a very basic support for traits/mixins behaviors apart of the Extension Methods.
Some say that it might bring a lot of bad designs habits but it is just like any other feature (e.g. sadly async/await are most of the time, misused).
By the way, I'm not really sure but I might have missed another extension related feature which is the Extension Constructors concept.
Anybody has ever heard of that one from MS?

@kbirger
Copy link

@kbirger kbirger commented Apr 29, 2015

This seems like a trivial thing to add. My understanding is that the IL must already support this since properties are just syntax sugar for getter/setter methods. This means MS must have not added it for a stylistic reason, or because they foresee it being abused in all the ways outlined by previous participants.

@h82258652
Copy link

@h82258652 h82258652 commented May 3, 2015

Wonderful, I think it will be really useful.
Take an example, we can add a extension property for enum. Like this:

public enum Gender
{
    Male,
    Female,
}

public class GenderPropertyExtension : ClassExtension<Gender>
{
    public string AdultName
    {
        get
        {
             return this==Gender.Male?"Man":"Woman";
        }
    }

    public string ChildName
    {
        get
        {
             return this==Gender.Male?"Boy":"Girl";
        }
    }
}

And I hope not only instance property can extension like current method extension. Static member also can extension.

@HaloFour
Copy link

@HaloFour HaloFour commented May 3, 2015

@kbirger Properties are mostly the accessor methods (there is a common naming convention but the runtime doesn't care) but they are also the additional metadata attached to the type that those accessor methods are a part of a property. There would be nothing stopping the compiler from recognizing and supporting that convention and making calls to get_MyProperty or set_MyProperty feel like a property called MyProperty, but for the purposes of reflection, data-binding, etc., that property would not exist.

I like the idea of extension properties and I think that they would make a lot of syntax cleaner feeling, but there are a couple of issues that concern me. For example, this mention of "state" or "extension fields". There'd really be no clean way to associate that data with the class instance itself, so the only way to really track that state would be through some kind of static dictionary. Such a pattern is a quick pit of failure into accidentally holding onto root references and preventing instances from getting collected ... ever.

@svick
Copy link
Contributor

@svick svick commented May 3, 2015

@HaloFour Wouldn't using something like ConditionalWeakTable be a solution to the GC issue?

@HaloFour
Copy link

@HaloFour HaloFour commented May 3, 2015

@svick Of course, there are numerous ways to solve the technical problem, but the issue is that someone needs to be aware that it is a problem before they attempt to solve it. Making the concept of state (e.g. extension fields) an official part of the language where the compiler automatically implements best practices could solve for that. But even so the idea of "extension state" just feels ... icky ... to me.

Granted, WPF already has the concept and an extension property syntax would work quite well with attached dependency properties I think.

@lukasf
Copy link

@lukasf lukasf commented Jul 1, 2015

Adding state to a class will always come with a rather huge performance penalty. I am pretty sure they will not do this as it is very bad practice. Additionally, such properties would not take part in any kind of data binding and no PropertyChanged notifications would be raised. I do not see much benefit in extension properties. When you don't add state, you can get more or less the same behavior by just adding extension Get/Set methods.

But static extension methods would be awesome. They would allow us to extend popular classes such as Math, Task, Assert, with more static methods, without the need for a new name ("..Ex").

@sharwell
Copy link
Member

@sharwell sharwell commented Jul 1, 2015

Adding state to a class will always come with a rather huge performance penalty. I am pretty sure they will not do this as it is very bad practice. Additionally, such properties would not take part in any kind of data binding and no PropertyChanged notifications would be raised.

Attached dependency properties already work with data binding. One example is TextOptions.TextRenderingMode, which must be accessed in code using GetTextRenderingMode and SetTextRenderingMode. If extension properties existed, the C# code could get and set a TextRenderingMode property instead, with exactly the same underlying behavior for the binding engine.

ConditionalWeakTable<TKey, TValue> already allows users to associate new state with an instance of a class. However, not all properties require the addition of state; extension properties could be equally reasonable in those cases as well.

@HaloFour
Copy link

@HaloFour HaloFour commented Jul 1, 2015

Well they only work with WPF's flavor of data-binding because that's how WPF was designed. IIRC no other form of data-binding in .NET recognizes that WPF-specific concept.

@TonyValenti
Copy link

@TonyValenti TonyValenti commented Sep 5, 2015

@sgjsakura -
I really like your proposed syntax for extension properties. I would like to see indexed properties for regular classes as well.

@Thaina
Copy link

@Thaina Thaina commented Sep 9, 2015

I support indexer style. And it should allow naming indexer property

I mean if code like this

public static class MyClassExtensions
{
 public static int GetData[this MyClass obj, int index]
 {
   get { return 0; }
   set { return; }
 }
}

It should be used

var data = myObj.GetData[0];
myObj.GetData[0] = 0;

Also I wan to suggest to allow property indexer too with the same syntax

@grwGeo
Copy link

@grwGeo grwGeo commented Oct 22, 2015

@sharwell Take a look at #3357 for the concept of "extension everything" to see how far extensions can go... I am a fervent supporter of extensions. I believe they should be part of legitimate OOP.

@grwGeo
Copy link

@grwGeo grwGeo commented Oct 23, 2015

@HellBrick , @chrisaut Attaching state to an object is perfectly valid and intuitive, as long as we understand what it means and how it should be used. The idea behind type extensibility is mainly to intervene into the inheritance chain and attach members (any members: fields, properties, indexers events etc.) that will be visible throughout the chain.

The main class is not aware of the extensions and the extension is a an independent class of its own with a weak reference to an instance of the main class. It can only see the visible interface of the main class and interact with it. Understanding this is the basis for proper usage of type extension. Like any feature it can be misused but as I believe it has logical coherence it should not be prone to abuse.

I hope I see this feature soon. I have plenty of uses for it, especially in controls.

@MadsTorgersen
Copy link
Contributor

@MadsTorgersen MadsTorgersen commented Aug 15, 2016

This is part of #11159. Closing as duplicate.

@jeme
Copy link

@jeme jeme commented Dec 13, 2016

Just scooping in some opinions.

@chrisaut

But, doing just that is a "natural" requirement/expectation if you want extension properties (and events)..

For events, perhaps, but not necessarily for properties, granted setters might be more rare but they could occur natural to have a single setter that would change multiple properties underneath.

Otherwise you cannot do auto-properties (compiler needs to emit a backing field), which may make the feature feel incomplete again.

Why would that make it incomplete?... Does the limitations of extension methods compared to true instance methods make them feel incomplete?...

Even if that were disallowed, if you still allow property setters, developers will try to come up with their own solution and half of them will get it wrong in subtle ways. For instance they may create a Dictonary<MyClass, string> and store it there. Ooops, now the instance can never be garbage collected and you created a nice leak. Most developers don't even know about weak references or ConditionalWeakTable.

Considering that it's already perfectly possible to shoot your self in the foot like that with extension methods, I really don't see that extension properties will be the defining difference here. Those who will do that has already passed a stop sign in declaring a static reference to a collection with references to their objects, if they do that without thinking twice I think they will just go ahead and implement the "SetMagicProperty(this SomeClass key, object value) { map[key] = value; }" method... Which C# will happily let you do.

So if we really want to discourage attaching additional state (essentially we don't want extension fields), then I feel the only way is to explicitly only allow Property Getters, and not support Setters or even getter only auto properties.

I really don't see any reason not to allow Setters when we considering that they are really just specially named methods under the hood with some meta data information.


Adding state to a class, e.g. though extension fields feels extremely natural and is very useful (consider dynamic languages). But I can certainly imagine that is has some extreme implications on the CLR, so here I would let the team make the call to weather or not to support them, I would probably stay away from them for now.

@MelbourneDeveloper
Copy link

@MelbourneDeveloper MelbourneDeveloper commented Nov 3, 2017

Yeah sharing code in XF is a real pain because this feature does not exist. All the code in WPF, Silverlight, and UWP uses "DataContext", but the same thing in Xamarin Forms is inexplicably "BindingContext". If I could put an extension property on all BindableObjects, immediately, code sharing would be a lot easier.

@lukasf
Copy link

@lukasf lukasf commented Nov 5, 2017

@MelbourneDeveloper: Extension properties are not real properies. They cannot be seen by reflection on the target object, so they will not be picked up by any data binding based framework such as Xaml UWP or Xamarin Forms. This will not help you in any way.

@Groostav
Copy link

@Groostav Groostav commented Mar 16, 2018

I'd like to point out that my favourite use case for this feature is/will-be extension properties on DataRow's, which, imho, very elegantly puts to bed the issue of spelling-mistakes (or worse, index-mistakes) on these all-too-popular data objects.

@roji
Copy link
Member

@roji roji commented Mar 16, 2018

@Groostav patching a weakly-typed API like DataRow by adding strongly-typed extensions to it is, well, a bit sad... Dapper (or a full-fledged O/RM) does sound like a better option...

@CatGirlsAreLife
Copy link

@CatGirlsAreLife CatGirlsAreLife commented Aug 1, 2018

This would be great because I do not want to derive from System.Reflection.Assembly to hope that my overridden Location property only works from an assembly loaded from a zip file.

What I would like is something liek this:

public sealed class ZipAssembly
{
    private string _location;

    public static string Location => _location;

    public static Assembly LoadFromZip(string ZipFilePath, string EntryFilePath, bool LoadSymbols)
    {
        // my code to get the assembly and debugging symbols data to byte array.
        // if LoadSymbols is false and running in debug mode reset to true.
        Assembly assembly = LoadSymbols ? Assembly.Load(assembytes, symbolbytes) : Assembly.Load(assembytes);
        assembly.LocationExtension += Location;
        return assembly;
    }
}

which would be nice for those wanting to override the original behavior of the System.Reflection.Assembly.Location to return what they want without extensive hacking on it. However tgat would mean all frameworks having that class would need to add LocationExtension to that class and the class that does the actual code providing the current functionality to do like:

if (LocationExtension != null)
    location = // invoke the property provided as LocationExtension here somehow.

- if (location != null)
+ if ((location != null) && (LocationExtension == null))
    // some location permissions or something according to the .NET Framework 4.7.2.

return location;

On it’s getter. And in this way, it only provides the extension override when and only when a file is loaded from the static LoadFromZip method.

After some thought I think ot would be better to make it a paramiterless method and then use the invoke function I think.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet