Extension Methods: Static Electricity?

As Anders pointed out in his Channel9 demo, Extension Methods in C# 3.0 really make Linq possible. After drilling into Extension Methods and wanting to not like them, I must ask: what were the alternatives The example that Ian Griffith's gives of some 3rd party developer quietly including something like:

namespace System
{
    public static class Evil
   {
        public static void Print(this object s)
        {
            Console.WriteLine(s);
        }
    }
}

Seems horrifying to say the least. I have to ask what the alternatives were.

Why not maybe :

namespace MyNameSpace
{
   public class extend System.Array
   {
      public System.Array Slice();
   }
}

The concept would be phlosophically similar to the new partial capability in C# 2.0. Just looking for some general comments here. I am worried (possibly needlessly) that the "killerness" of Linq might come at the cost of non-determinism becasue of the use of statics.


Answer this question

Extension Methods: Static Electricity?

  • Sirus Softs Inc.


    I don't see the horror in the allegedly Evil class.  WriteLine accepts object, and in fact is used quite often.  Defining a Print() method applicable to object, while gratuitous, doesn't raise any technical alarms for me.  Where's the non-determinism   Everything is resolvable, and as with generics a method so defined isn't exercising APIs it wouldn't otherwise have access to, so even security is maintained.

    The only problem I have at the moment is that there's no simple way to selectively use a single extension method from a set of methods defined in an assembly.

    This whole extension method mechanism has been used in other languages, and well, for some time.  I don't enjoy having to sprinkle explicit static statements all over the source, but I certainly don't see the problem with the methods *as compiled* being static.


  • insanepickle

    Well, let's say you have this class

    public class Foo {
    public int Number;
    }

    you could add these pseudo-properties

    public static class MyExtensions {
    public static int GetDoubleNumber(this Foo self) {
    return self.Number * 2;
    }
    public static void SetDoubleNumber(this Foo self, int value) {
    self.Number = value / 2;
    }
    }

    and then say

    Foo myFoo = new Foo();
    myFoo.SetDoubleNumber(100); // myFoo.Number is now 50
    int x = myFoo.GetDoubleNumber(); // x is now 100

    Note that in this example I'm doing some trivial math in the pseudo-properties. That's because, since "Number" is already a public member of Foo, it's kind of pointless to wrap its access in a property unless you're doing some other work to make it worthwhile.

    If you're really interested in "attaching" a property to an object (that is, making it seem like it has a member it doesn't intrinsically have), you'll have to store the value of that property yourself:

    public static class MyFakeProvider {
    private static Dictionary<Foo, string> propertyCache;
    private static MyFakeProvider() {
    propertyCache = new Dictionary<Foo, string>();
    }
    public static string GetName(this Foo self) {
    if(propertyCache.HasKey(self) {
    return propertyCache[self];
    } else {
    return null;
    }
    }
    public static void SetName(this Foo self, string value) {
    propertyCache[self] = value;
    }
    }

    You'll therefore have to deal with the problems of stray object references (your cache will carry a reference to every "tagged" object you touch, and therefore will keep them from being garbage-collected) and such, but you get the idea.



  • RESAI AHMET CUBUKCU

    I see your point.

    Maybe there should be an alternative to 'using'

    Something like:

    using extensions System.Query;
     

    This would avoid 'accidental' use of extensions.


  • wakeup

    I think they said it's something they're considering.  It'd make a nice code-side alternative to the extension providers like Help and Tooltip.

  • LaVinci

    Correct, but you get *every* extension method in the namespace activated.  What if I have two third party extension method libraries for collections, each defining many things, but both defining Foo().  I want to select which version of Foo() to apply -- there's no direct support for that at the moment.


  • ertobias

    In order for them to be able to add properties to a type, wouldn't the extensions have to change from Static members to Instance members I don't see the utility in having a Static 'property' so to speak.

    If that's the case, how would this be implemented What would the ramifications be in terms of object encapsulation Would Instance Extension Members be able to modify protected or private fields of an object, or call protected or private methods

    As I understand it, when C# code is compiled that makes use of Extension methods, the compiler just translates the extension method into the applicable Static method call. Is this view correct The compiler doesn't do any weird tricks at the moment, does it And if not, how will that change if you do move to Instance Extensions

    I can think of a use for an Instance Extension Property right now, matter of fact. I recall in my VB 6.0 days that almost all controls had a 'Tag' property of type Object that is kinda missing from most objects nowadays. It'd be great to be able to extend objects to include such a property.

    Sorry for so many questions. :P Very curious, I am, yes...


  • vsnk

    The extension methods are defined as static, yes, but in practice they're syntactically non-static (that is, they're called as if they were instance methods). So a property would be handled identically.

    An extension method defined as

        public static class MyExtensions {
            public static int GetValue(this Foo self) {
                return self.something;
            }
        }

    and called as

        Foo obj = new Foo();
        int x = obj.GetValue();

    is compiled as if it was

        int x = MyExtensions.GetValue(obj);

    It's static only with respect to "MyExtensions". In use, though, it's compiled against the instance obj, making it "look" like an instance method. Since it's external to obj, it can only access public members, so encapsulation isn't broken. What we'd like in a property is to make it

        public static class MyExtensions {
            public static int Value(this Foo self) {
                get { return self.something; }
            }
        }
        int x = obj.Value;

    which is only a minor change.

     



  • Aman JIANG

    It's not the accidental use of extensions.. it's the lack of granularity.  What I'd like would be closer to:



    extend with <Namespace1> // extend all applicable using Namespace1
    extend with <Type1> // extend all applicable using Type1
    extend with <Type2>.<Method> // extend all applicable with one particular Method
    extend <TypeX> with <Namespace2> // extend TypeX using Namespace
    extend <TypeX> with <Type3> // extend TypeX using another Type
    extend <TypeX> with <Type4>.<Method> // extend TypeX with one particular Method

     


    ... because sometimes you want to use your own method to extend a 3rd party Type, and you want to manage conflicts with other extensions.

  • startingVBNet

     Keith Farmer wrote:

    The only problem I have at the moment is that there's no simple way to selectively use a single extension method from a set of methods defined in an assembly.


    I thought that the scope was namespace not assembly. In other words, by adding


    using System.Query;
     


    I get the extensions method defined within the namespace System.Query.


  • BobConsultant2

    If you want to use a specific version of an extension where multiple are available you can either use type specificity (IEnumerable<int> is more specific than IEnumerable<T> therefor is used) or explicitly call the static class that defines the extensions:



    using System.Query;
    using MyQuery;
    ...

    var q = list.Where(...);
    var q = Sequence.Where(list, ...);
    var q = MySequence.Where(list, ...);

     



  • Erik Poirier

    So in my example of an Extension member that might add a 'tag' property to an object, how would I implement this currently

    I understand that I can't add a property - but I can add "get" and "set" methods that kind of emulate one. Knowing that the Extensions are static, how would I implement this against all instances of a particular object

    Assuming the Tag "property" has a signature like this:

    static int GetTag(this object obj);
    static void SetTag(this object obj, object tag);


  • james_cline_

    I agree. This would definitely make sense.

  • Shedal

    My personal desire would be to just give up and implement extension keywords:

    public void FooMethod(int x) extends Bar bar
    {
      doSomething(bar, x);
    }
    
    public string TextRot13 extends Bar bar
    {
      get
      {
        return Rot13(bar.Text);
      }
    
      set
      {
        bar.Text = Rot13(value);
      }
    }
    


  • FourT2

    Just a question. Could I use Extensions to add properties to an object And if so, how will the object serialize if I do this
  • Extension Methods: Static Electricity?