Add Extension properties

Topics: C# Language Design
Apr 7, 2014 at 12:47 PM
This is something old, as Eric Lippert did explain why Extension Properties didn't come to C#4
http://blogs.msdn.com/b/ericlippert/archive/2009/10/05/why-no-extension-properties.aspx

Still, reasons explained in this post were not really valid, as the WPF property model has little in common with extension properties (dynamic attached properties vs static properties known at compile time)

I haven't dig into the problem, not sure if extension properties are requiring more work on the current method extension model, but would love to use them! We often end-up to use a method GetXXX() for this, but this is really not streamlined compare to a real property.
Apr 7, 2014 at 12:58 PM
I'd be interested in seeing this. C# allows "extending" types through functions, and "extending" "data" would mean that you could fully customize existing methods.

If this was supported, I'd also like to see the ability to declare interfaces for existing types (like int), then the type system in C# wouldn't feel constrained at all.
Apr 7, 2014 at 10:37 PM
How would you propose this to be implemented?
Apr 8, 2014 at 12:46 AM
PauloMorgado wrote:
How would you propose this to be implemented?
Good question! :)

If I had to redesign the whole extension properties from scratch, I would rather use this kind of syntax where the this pointer is implicit and you can only declare extensions inside the scoped extender (List<T>)
extends List<T>
{
    public void Flip()
    {
        for(int i = 0; i < Count - 1; i++)
        {
            var temp = this[i];
            this[i] = this[i+1];
            this[i+1] = temp;
        }
    }
    
    public int CountPer4
    {
        get
        {
            return Count / 4;
        }
    }
}
But with the current design, property extensions syntax is a bit problematic to add (but maybe as the C# team worked on this in the past, they have dig into this and found neat syntaxes). Though I would try to use explicit implementation syntax for properties, something like this:
public static class ListExtensions
{
    public static void List<T>.Flip()
    {
        for(int i = 0; i < Count - 1; i++)
        {
            var temp = this[i];
            this[i] = this[i+1];
            this[i+1] = temp;
        }
    }
    
    public static int List<T>.CountPer4
    {
        get
        {
            return Count / 4;
        }
    }
}
Apr 8, 2014 at 9:35 AM
The first option might work for VB:
Public Module ListExtensions

    Public Property CountPer4 As Integer Extends List<T>
        Get
            Me.Count / 4
        End Get
    End Porperty

End Module
Because thy are extension methods, not extension classes.

The second, however, seems to be a good proposal for a new extension member syntax for C#.
May 2, 2014 at 3:50 PM
Yes more extensibility is something C# needs.
May 2, 2014 at 5:13 PM
Edited May 2, 2014 at 5:14 PM
Didn't see this thread and recently opened a new one. I'm really sorry.

https://roslyn.codeplex.com/discussions/543872
May 4, 2014 at 2:22 AM
Edited May 4, 2014 at 2:26 AM
Hi,

The extends keyword is pretty nice, though I don't really mind the this syntax. It's very familiar now.

So how about the following syntax for extension properties and indexers?

(Edit: Shortened the name of the indexer so that it doesn't wrap)
static class Extensions
{
    public static int LastIndex<T>(this IList<T> list)
    {
        get
        {
            return list.Count - 1;
        }
    }

    public static T Last<T>(this IList<T> list)
    {
        get
        {
            return list[list.LastIndex];
        }
        set
        {
            list[list.LastIndex] = value;
        }
    }

    public static T IndexByString<T>(this IList<T> list, string index)
    {
        get
        {
            return list[int.Parse(index)];
        }
        set
        {
            list[int.Parse(index)] = value;
        }
    }
}

// Usage
class Program
{
    static void Main()
    {
        var list = new List<string>() { "A", "B", "C" };

       Console.WriteLine(list.LastIndex);  // prints 2
       Console.WriteLine(list.Last);  // prints C
       list.Last = "D";
       Console.WriteLine(list.Last);  // prints D
       Console.WriteLine(list["1"]);  // prints B  -- calls IndexByString
    }
}
Notice that the driving factor in whether C# interprets the extension as a property or an indexer is merely the extension's cardinality. And since VB supports named property indexers, I believe, the name given in C# to an indexer extension could be exposed to VB.

- Dave
Coordinator
May 4, 2014 at 12:44 PM
Hey all,

I just wanted to share with you all that this is definitely a feature the language designers have thought about often. The biggest issue that comes up is that there's no way to declare a generic property. Either in VB/C# or the CLR. So while we can come up with a syntax for them there isn't actually a way to encode that in metadata. That would mean either limiting the feature to extending non-generic types, or specific constructions of generic types, or a new version of the CLR which would mean not being able to use it when targeting .NET 2.0 (a situation we're reluctant to create).

An alternate proposal would be to break with the way we declare extension methods today for a more general syntax. Perhaps opening the door for other kinds of extensions - extension constructors (factory methods)?, extension events?, extension operators?. Unfortunately that would add to the concept count of the languages as there would then be two ways of declaring an extension method - also something we're reluctant to do.

But we're not so reluctant to do it that we know we definitely wouldn't. Which makes us more hesitant on maybe trying to salvage the current way extension methods are declared and come up with some analogous named indexed property syntax like you've suggest above because that would only further commit the language to current model. In other words, we're stuck. And we're waiting patiently for revelation to hit us :)

Regards,

Anthony D. Green, Program Manager, Visual Basic & C# Languages Team
May 4, 2014 at 1:12 PM
First of all, let me say thank you to @ADGreen. I absolutely love how open C# went. It went from a totally closed box development to totally open source with program managers explaining where features are going on forums.

Secondly, there is definitely a predicament here. Redesigning the way extensions work totally is probably the route C# should take long term, but that means you can't do anything short term, which does suck.

Ideally extension methods, constructors, events, operators, indexers, properties and the like would be able to be declared using the above proposed extends syntax. Basically make it like partial except with a few restrictions (can't declare new fields, can't change base class or accessibility). I'd really like this syntax to be able to say a type implements a certain interface as well, which would allow us to extend other types to be used in generics (someone could finally create a generic Matrix class).

I think for now I'm okay with saying these features are put on hold while the team and the community determines the right syntax.

I think it'd be okay to limit the feature to non-generics in the first version, then release a subsequent version that does work with generics but requires a new CLR (you can do this with any other modifications you would like to the CLR. Perhaps supporting type equivalence as in TypeScript?).

If you do this then the feature wouldn't feel tied down to the new .NET, and people could use it for old versions, but then when you release the generic one, they'll get the distinction that generics don't work on older versions.
May 4, 2014 at 1:22 PM
If generic properties would require a new CLR version, maybe the next version of the CLR should be made to support it even if C# does not yet. That way, if C# much later adds support for generic properties the CLR on most machines will already support them. IOW this CLR change should probably be made at the earliest opportunity.
May 4, 2014 at 4:55 PM
Edited May 4, 2014 at 4:57 PM
@ADGreen: could you implement them as extension getters/setters with the compiler? (even if declared in source code as properties)

So when you get to something like:
public static T MyProperty: this myProperty
    where T: class, new()
{
   get { ... }
   set { ... }
}
The compiler changes it to:
public static T _getMyProperty (this T myProperty)
   where T: class, new()
{
   ...
}
Ditto for the setter.
May 4, 2014 at 5:05 PM
Edited May 4, 2014 at 5:43 PM
Hi ADGreen,

Thanks so much for responding and explaining the current problems with this feature proposal.
The biggest issue that comes up is that there's no way to declare a generic property. Either in VB/C# or the CLR. So while we can come up with a syntax for them there isn't actually a way to encode that in metadata.
Why is that necessary though? In my examples, the only generic type argument is T and it's used only to identify the interface being extended, IList<T>. So the only metadata needed would be e.g., the same that is used on ICollection<T>.get_Count or IList<T>.this[int]. Isn't that enough? In other words, it sounds to me like you're struggling with the problem of extra generic type arguments that aren't used merely to identify the type being extended. Perhaps that could be useful in extension indexers, but couldn't the compiler simply disallow it for now?
static class Extensions
{
    public static int Foo<T, U>(this IList<T> list, U indexerArg)
    {
        get  // compiler error
        {
            return list[Convert.ChangeType(indexerArg, typeof(int))];
        }
    }
}
hesitant on maybe trying to salvage the current way extension methods are declared and come up with some analogous named indexed property syntax like you've suggest above because that would only further commit the language to current model
I agree that's a problem but I don't think that in the future having two syntaxes for extension methods, properties and indexers is all that bad. Think of the future syntax, such as the proposed extends keyword, as simply lowering the feature. The this keyword is merely a raised syntactic sugar that came first because it's technically more versatile for the few extensions it supports, since you only need to define a single static class as the container rather than extending one type at a time.

- Dave
May 4, 2014 at 11:17 PM
Edited May 4, 2014 at 11:29 PM
ADGreen wrote:
Hey all,

I just wanted to share with you all that this is definitely a feature the language designers have thought about often. The biggest issue that comes up is that there's no way to declare a generic property. Either in VB/C# or the CLR. So while we can come up with a syntax for them there isn't actually a way to encode that in metadata. That would mean either limiting the feature to extending non-generic types, or specific constructions of generic types, or a new version of the CLR which would mean not being able to use it when targeting .NET 2.0 (a situation we're reluctant to create).
What are properties other than a language-agnostic form of metadata which specifies that certain methods should be invokable with property syntax? Is there any reason that something that looks like a property in source code would have to be a "property" in the CLR?

If the C# compiler would process an attempt to read property Moo on on an object of type Foo which had no such property as an invocation of a statuc method static someType get_Moo(Foo it) [assuming such a method existed], and an attempt to write the property as an an invocation of set_Moo(Foo it, someType value), the CLR wouldn't have to worry about it. Such an implementation of extension properties would allow them to support things which present properties do not. [Incidentally, I'm not sure what properties accomplish that couldn't be accomplished just as well by having functions starting with get_ or set_ include an attribute which would say that they should be usable as properties].

Incidentally, a couple changes I would like to see to extension methods would be to
  1. Allow a type to declare extension methods upon itself; while there's certainly value in allowing an extension method to be declared without requiring support from the type of their argument, there are other cases where it may be helpful for a type to declare extension methods upon itself without requiring the importation of some other type. For example, if such a feature had existed from the beginning, it would have been possible to whether someString was null or emtpy via someString.IsNullorEmpty() rather than String.IsNullOrEmpty(someString).
  2. Allow a type to declare private or protected extension methods which would be useful only within the type, and which could use private and protected members of its type. A public extension method within a generic type wouldn't make much sense (what type parameters should be assumed for the enclosing class when it's invoked from outside that class?) but if the method is private or protected, no such ambiguity would arise. If the method is declared within Foo<T> and is only invokable within Foo<T> or descendants thereof, then the type of T should be whatever it is in the invoking code.
May 6, 2014 at 12:11 PM
An alternate proposal would be to break with the way we declare extension methods today for a more general syntax. Perhaps opening the door for other kinds of extensions - extension constructors (factory methods)?, extension events?, extension operators?.
I just want to note that while most of those sound really uncommon, one thing that would be actually nice to have would be extension methods to static classes. There are at least two significant usages:
  1. Extending Assert in most unit-testing frameworks
  2. Extending BCL classes in intermediate BCL releases, e.g. having this in language would remove the need for TaskEx in pre-4.5
May 6, 2014 at 1:08 PM
@ashmind, what are you really proposing? Can you show some syntax of declaration and consumption?

With the ability to import static members to the global namespace that could be worked around.

I'm not a big fan of that feature and besides Math, Assert is one of the classes that makes some sense to use without qualifying with the class name. Although I like Assert.IsEqual over just IsEqual.

Instead of extending static classes, what about multi-target aliases?
using Linq = System.Linq;
using Linq = System.Data.Linq;
using Linq = System.Xml.Linq;

using Task = System.Threading.Tasks.Task;
using Task = System.Threading.Tasks.TaskEx;
May 6, 2014 at 3:01 PM
I think static extension methods are much more useful than extension properties/events/etc. So much so, in fact, that I made an issue for it a while back. This is possible in VB currently, it seems like it should be added to C#. As I mentioned in the issue, I think extending the Math class is one of the best use cases.

@PauloMorgado Your solution would result in more name collisions, as method names in one class are unlikely be written with the method names from another class in mind. With static extension methods, the author must plan so that the methods they're adding fits in with the method names already present in the class they're extending.
May 6, 2014 at 5:25 PM
MgSam wrote:
I think static extension methods are much more useful than extension properties/events/etc. So much so, in fact, that I made an issue for it a while back. This is possible in VB currently, it seems like it should be added to C#. As I mentioned in the issue, I think extending the Math class is one of the best use cases.

@PauloMorgado Your solution would result in more name collisions, as method names in one class are unlikely be written with the method names from another class in mind. With static extension methods, the author must plan so that the methods they're adding fits in with the method names already present in the class they're extending.
Bringing stuff to the global namespace has the potential of resulting in more collisions. Is that what you're referring to? Because I don't see, for any practical reasons, how multi-target aliases can result in more collisions than your proposal.

Bare in mind that although the author of the extending class has in mind the method names of the extended class, the author of the extended class has no knowledge of any extensions. So any update to the extended class might result in collisions.

Would you agree that a feature that you would like to have and not an issue?
May 7, 2014 at 1:31 PM
Bare in mind that although the author of the extending class has in mind the method names of the extended class, the author of the extended class has no knowledge of any extensions. So any update to the extended class might result in collisions.
That's true, but in practice, the extended class is probably not updated very often, that's why it's being extended in the first place. (When was the last time System.Math got new functionality?) With static extension methods, at least one of the two authors has the names of the other class in mind; in your proposal you are mixing members ad-hoc.

Making it an "issue" is so that people can vote on it. (One day CodePlex engineers will invent the down vote button to make this process more effective). Most projects on CodePlex use the issue tracker as a combination bug tracker/feature request tracker.
May 7, 2014 at 1:49 PM
MgSam wrote:
That's true, but in practice, the extended class is probably not updated very often, that's why it's being extended in the first place. (When was the last time System.Math got new functionality?) With static extension methods, at least one of the two authors has the names of the other class in mind; in your proposal you are mixing members ad-hoc.
If I would choose to extend Math it wouldn't be because of how often it is updated but because I can't update it myself.

When a developer imports a namespace she/he is importing all extension methods of all referenced assemblies in that namespace whether she/he wants it or not. The way I propose would make it always intentional. I always prefer intentional over accidental.
Making it an "issue" is so that people can vote on it. (One day CodePlex engineers will invent the down vote button to make this process more effective). Most projects on CodePlex use the issue tracker as a combination bug tracker/feature request tracker.
Got it! Discussions could use upvote and downvote and polls would be a nice to have too.
May 7, 2014 at 3:21 PM
MgSam wrote:
I think static extension methods are much more useful than extension properties/events/etc.
Is the real goal to allow code to e.g. use Math.whatever(x) without having to clutter the expression with the detail of whether a method is actually in Math or SamsMathExtension.*? If so, I think that it would be even more helpful to be able to say something like:
double foo{double x1, double y1, double x2, double y2)
{
   using alias (Sqrt=Math.Sqrt, Pow2 = SamsMathExtensions.Pow2)
   {
     return Sqrt(Pow2(x2-x1)+Pow2(y2-y1));
   }
}
With using alias being available both inside and outside method scope. Importing aliases which conflict with existing class members would not be an error unless an attempt was made to use that identifier. Use of an identifier which could refer either to an imported alias or a class member, or to more than one imported alias, should be an error unless a variant of using alias is used which expressly gives the imported aliases higher or lower priority than any pre-existing ones.

The fact that extension methods hide the real location of the code being invoked is ugly, but is an arguably-necessary aspect of having method availability key off the instance type. I don't see the same imperative with static methods; cluttering expressions with details of where methods are imported from impairs readability, but I think having the specification of where methods come from located near the expression would be better than having the compiler simply look for them wherever it could find them.
May 7, 2014 at 3:47 PM
@supercat: regarding your suggestion, I'd instead prefer something like:
double foo{double x1, double y1, double x2, double y2)
   using Sqrt = Math.Sqrt
   using Pow2 = SamsMathExtensions.Pow2
{
   return Sqrt(Pow2(x2-x1)+Pow2(y2-y1));
}
May 7, 2014 at 4:15 PM
I like it. Would the using blocks in a method header behave analogously with those in a namespace header? Would the aliases defined within a method header affect types used earlier in that header? I don't especially like having type-related declarations late in a header affect things near the beginning, but Foo<T>(parameters) where T:whatever establishes that as normal practice.
May 7, 2014 at 4:21 PM
Edited May 7, 2014 at 4:22 PM
Well, I guess it should follow a cascade-typeof checking, not as an error but as a warning to the programmer, and the alias you define for the method overrides the one defined for the whole class when you declare the same alias. Yes, I avoided suggesting "where" to make it clearly separated from generics.
May 7, 2014 at 5:01 PM
Ultrahead wrote:
Well, I guess it should follow a cascade-typeof checking, not as an error but as a warning to the programmer, and the alias you define for the method overrides the one defined for the whole class when you declare the same alias.
If an alias can introduce more than one method (bear in mind the existence of overloads!) I think there should be a clear syntax to indicate whether the programmer intends for the aliases to blank any existing like-named methods, overrule the conflicting overloads, or merely fill in any gaps; I would also favor a means (perhaps the default) which would say that no conflicts are expected. If it would be desirable for the default not to cause errors in case conflicts arise, one could have the default say "Programmer isn't aware of conflicts; if any arise, use the alias but give a warning", while having an alternate syntax to say "Programmers expects that there are no conflicts. If any conflicts exist, *an unexpected condition exists, and any behavior other than an error would be contrary to programmer's expectations".
Yes, I avoided suggesting "where" to make it clearly separated from generics.
I think a syntax proposal should make clear what effect the ordering of using clauses relative to other clauses should have, and what restrictions there should be.
May 7, 2014 at 5:13 PM
Ultrahead wrote:
@supercat: regarding your suggestion, I'd instead prefer something like:
double foo{double x1, double y1, double x2, double y2)
   using Sqrt = Math.Sqrt
   using Pow2 = SamsMathExtensions.Pow2
{
   return Sqrt(Pow2(x2-x1)+Pow2(y2-y1));
}
I like that. Allow me to tweek it:
using ...;
namespace N
{
    using ...;
    class C
    {
        using ...;
        void M()
        {
            using ...;
        }
    }
}
May 8, 2014 at 12:48 PM
PauloMorgado wrote:
I like that. Allow me to tweek it:
For parallelism with the earlier suggested form, the using declarations should go before the opening brace of each class or namespace.
May 8, 2014 at 3:28 PM
supercat wrote:
PauloMorgado wrote:
I like that. Allow me to tweek it:
For parallelism with the earlier suggested form, the using declarations should go before the opening brace of each class or namespace.
Which was not compatible with current uses of the using directive.
May 8, 2014 at 4:45 PM
PauloMorgado wrote:
Which was not compatible with current uses of the using directive.
Are there any cases where the IDisposable style of using doesn't require a left parenthesis immediately after the using token, or where the "imports" style can accept a left-paren? I like your syntax better, but I think either could be added without breaking anything.
May 8, 2014 at 5:07 PM
supercat wrote:
PauloMorgado wrote:
Which was not compatible with current uses of the using directive.
Are there any cases where the IDisposable style of using doesn't require a left parenthesis immediately after the using token, or where the "imports" style can accept a left-paren? I like your syntax better, but I think either could be added without breaking anything.
The using keyword is used as a directive and as a statement. The only thing the directive and the statement have in common is the using keyword.

What Ultrahead is proposing another scope for the using directive (method) to which I just added another one (type) and "corrected" the syntax.
May 8, 2014 at 8:17 PM
PauloMorgado wrote:
supercat wrote:
What Ultrahead is proposing another scope for the using directive (method) to which I just added another one (type) and "corrected" the syntax.
What do you think about placement inside a method scope, as with the last example? If the directive appears between a type or method header and its body, it will be clear that it affects just the body that follows. Allowing it to appear within a method body might make it less clear whether it affects the scope in which it appears, or only affects the following statement.
May 8, 2014 at 9:47 PM
supercat wrote:
PauloMorgado wrote:
supercat wrote:
What Ultrahead is proposing another scope for the using directive (method) to which I just added another one (type) and "corrected" the syntax.
What do you think about placement inside a method scope, as with the last example? If the directive appears between a type or method header and its body, it will be clear that it affects just the body that follows. Allowing it to appear within a method body might make it less clear whether it affects the scope in which it appears, or only affects the following statement.
Why come up with yet another syntax?

using directives are the first instructions of a code file or the first instructions of a namespace "body". The same could be applied to types and methods.