Tech Off Thread

131 posts

Ideas for C# 5.0

Back to Forum: Tech Off
  • User profile image
    Ion Todirel

    exoteric said:
    exoteric said:
    *snip*

    So let me boil it down to its absolute undeniable essence

     

    STuple pros

    - structs; for performance reasons (makes sense for tuples as most tuples are less than 10 elements)

    - recursion; for composition (tuple.Rest rather than new Tuple<A,B>(tuple.Item1, tuple.Item2); to be fair: representation bias)

    - enumeration; for composition (use tuples directly as sequences which, intuitively they are)

     

    Tuple pros

    - classes; for nominal typing (: INominal<T>)

    - flatness; for ease of comprehension and simplicity

    - non-enumeration; unmistakeable distinctness, no accidental application of abstraction

     

    The tension here is somewhat like structural vs nominal typing. Is it a duck if it looks, walks and quacks like a duck or is it only a duck if it has duck painted over it?

     

    These are choices. Being aware that there are choices being made for you and what the trade-offs are, is useful. I'm sure there are good reasons for the current design - nevertheless it is interesting to examine other paths of expression

     

    Smiley

    > recursion; for composition (tuple.Rest rather than new Tuple<A,B>(tuple.Item1, tuple.Item2); to be fair: representation bias)

    I would call .Rest.Rest.Rest.* a bad design rather than a different representation, get a better name and I may change my mind Tongue Out

     

    > enumeration; for composition (use tuples directly as sequences which, intuitively they are)

    And how are you going to enumerate them, return a IEnumerable<object>? That surely ain't cool.

     

     

  • User profile image
    exoteric

    Ion Todirel said:
    exoteric said:
    *snip*

    > recursion; for composition (tuple.Rest rather than new Tuple<A,B>(tuple.Item1, tuple.Item2); to be fair: representation bias)

    I would call .Rest.Rest.Rest.* a bad design rather than a different representation, get a better name and I may change my mind Tongue Out

     

    > enumeration; for composition (use tuples directly as sequences which, intuitively they are)

    And how are you going to enumerate them, return a IEnumerable<object>? That surely ain't cool.

     

     

    (1) homogeneous tuples: Tommy already showed how you can enumerate them using extension methods. These are fully typed so no problem there. The next step is to define GetEnumerator as part of tuple itself and define it only for homogenous tuples -or- : given a foreach which would accept type-parametric extension methods, you could just define it as GetEnumerator<T, ...> extension methods.

    static where possible
    - nominal too!

    (2) heterogeneous tuples; as mentioned previously, you can simply use dynamic. In this case you want to be extremely careful of course but you will not have to insert casts; in fact you may want this to be defined as extension methods from a nested namespace (System.Dynamic[.Tuple] or System.Tuple.Dynamic) so it isn't automatically imported; or even be able to except some extension methods for a particular variable... well ok, that's extreme

    dynamic when necessary
    - structural too!

    The name Rest is not so important, although I like it (and it rhymes with Best - beat that!). Of course Rest could also be defined for tuples as they are defined today (Tuple<T, ...>), it just so happens it isn't. I wouldn't call a design bad because of a name but of course names are important in the final design; I've not picked the names with respect to a broader audience; such "streamlining" is not really interesting in the initial design phase, more of a distraction.

  • User profile image
    contextfree

    Vriff Polo said:

    First class dependency objects and properties;

     

     

    public dependency class Person
    {
    	public dependency string Name 
    	{ 
    		get;
    		set; 
    		default { return "John Doe"; }
    		change { Console.WriteLine("Old: {0}, New: {1}", oldvalue, newvalue); }
    	}
    }

     

     

    instead of

     

     

    public class Person: DependencyObject
    {
    	public static readonly DependencyProperty NameProperty = DependencyProperty.Register(
    		"Name", typeof(string), typeof(Person), new PropertyMetadata("John Doe", OnNameChanged));
    	
    	private static void OnNameChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    	{
    		((Person)sender).OnNameChanged((string)args.OldValue, (string)args.NewValue);
    	}
     
    	public string Name
    	{
    		get { return (string)GetValue(NameProperty); }
    		set { SetValue(NameProperty, value); }
    	}
    	private void OnNameChanged(string oldvalue, string newvalue)
    	{
    		Console.WriteLine("Old: {0}, New {1}", oldvalue, newvalue);
    	}
    }

     

    Would be nice if something like this could also work with INotifyPropertyChanged, IDataErrorInfo and IEditableObject.

     

    I like tuple syntax, but I kinda feel it fails the -100 point test for C#.  re enumeration of tuple values, this seems more of a metaprogramming kind of feature and actually can't you do it with reflection even now?  actually, isn't this more or less equivalent to serialization?

     

     I would definitely like to see some kind of language feature that makes declarative dataflow and data binding less awkward.  It doesn't have to be direct support for the WPF dependency property system -- although I'd personally welcome that -- but maybe there's some more general feature that would still allow something like WPF dependency properties to be built on top of it and be syntactically nicer, though I can't think just what that would be at the moment.

     

    I would of course also welcome better support for non-nullable and immutable values -- and pure functions -- but I suspect this may have to wait for a successor language to C# (which might still be called C# as with VB6 -> VB.NET).

  • User profile image
    exoteric

    contextfree said:
    Vriff Polo said:
    *snip*

    I like tuple syntax, but I kinda feel it fails the -100 point test for C#.  re enumeration of tuple values, this seems more of a metaprogramming kind of feature and actually can't you do it with reflection even now?  actually, isn't this more or less equivalent to serialization?

     

     I would definitely like to see some kind of language feature that makes declarative dataflow and data binding less awkward.  It doesn't have to be direct support for the WPF dependency property system -- although I'd personally welcome that -- but maybe there's some more general feature that would still allow something like WPF dependency properties to be built on top of it and be syntactically nicer, though I can't think just what that would be at the moment.

     

    I would of course also welcome better support for non-nullable and immutable values -- and pure functions -- but I suspect this may have to wait for a successor language to C# (which might still be called C# as with VB6 -> VB.NET).

    Two questions for you contextfree Smiley

    - what is the -100 point test for C# (and how does it relate to any tuple syntax)

    - how is enumeration of tuples equivalent to serialization

  • User profile image
    Frank Hileman

    exoteric said:
    Frank Hileman said:
    *snip*

    Actually the language D has very sophisticated (transitive) const semantics.

     

    In many cases I think defining const-ness or immutability is a definition-site problem. If a type is inherently mutable, I'm not so sure it makes sense to force a new immutable version of it. Types should be designed to work as immutable or mutable and the type-system should maybe help you track if you let an impure object flow through a method call (e.g. by forcing you to mark the return type as Impure<T>.

     

    For example, if you let in an impure object in an otherwise pure method and you then compute some result based on it - but accessing properties of the object changes the object itself (let's just say it's an evil object), then this means that the method is still pure in a way but if you then call the same method again with the same object, it will break - because technically it's not the same object anymore. So the method is no longer reflexively pure.

    I agree with you. I would like to be able to specify the semantics of a data type or method more easily: should it be treated as immutable, or not (const). Should an argument be considered deeply const, etc. The compiler can take advantage of that and we can be free to break the rules, to add diagnostic fields to data types, for example.

     

    The main problem I have is the clumsiness of value semantics in c#. This is just language weirdness.

  • User profile image
    exoteric

    Frank Hileman said:
    exoteric said:
    *snip*

    I agree with you. I would like to be able to specify the semantics of a data type or method more easily: should it be treated as immutable, or not (const). Should an argument be considered deeply const, etc. The compiler can take advantage of that and we can be free to break the rules, to add diagnostic fields to data types, for example.

     

    The main problem I have is the clumsiness of value semantics in c#. This is just language weirdness.

    There is some elegance as well: auto-boxing and unboxing of values. <edit:wrong>On the other hand it is strange[1] that it's not possible to express that a struct (such as Tuple) conforms to an interface (such as IComparable<T>). Being a struct offsets you to a second-class[2] citizenship, stripped of priviledges such as interface inheritance.</edit:wrong>

     

    Constness is really about purity as immutable objects lead to purity. Structs render mutability a tiny bit better as you always pass around copies but if a struct is mutable then it's still fundamentally impure and assists in permeating impurity; at least in an impure setting; say you have a method that has a local variable that is a struct type, then mutating this should be no major issue but if, on the other hand, this struct is not local but ambient in the object, then mutating it will affect purity of the object.

     

    I believe D is working towards supporting notions of purity and the same with C# or maybe generally .Net in that I saw some special contract attributes for this somewhere (maybe).

     

    It's interesting to think about having types be pure but also having a special purity constraint on types which the type-checker can enforce. This is the inverse of what Haskell does: everything is pure unless it's not - and then you get trapped in the IO monad. It would be quite nice to have a similar formalism, if reversed, for .Net, where you could express Pure<T>.

     

    This would of course be a very special type, requiring compiler magic, depending on the power of the language itself; e.g. C# with a step in a multi-step compilation process for doing expression tree verification of static invariants such as purity; well, that's an advanced topic: allowing the programmer to extend the type-system/checker with arbitrary invariants; in a way we can think of contracts in this way too (it's just that many invariants can't be statically verified; but using types with more associated meaning would seem more powerful; somewhat like dependent typing perhaps.)

     

    [1] Not strange in a pragmatic sense (language evolution takes time) but weird in an idiological sense (absent a notion of time, one could argue about imperfections such as unnecessary non-uniformity between structs and classes; on the other hand[3])

    [2] Not a pun

    [3]Talk is cheap

  • User profile image
    Sven Groot

    exoteric said:
    Frank Hileman said:
    *snip*

    There is some elegance as well: auto-boxing and unboxing of values. <edit:wrong>On the other hand it is strange[1] that it's not possible to express that a struct (such as Tuple) conforms to an interface (such as IComparable<T>). Being a struct offsets you to a second-class[2] citizenship, stripped of priviledges such as interface inheritance.</edit:wrong>

     

    Constness is really about purity as immutable objects lead to purity. Structs render mutability a tiny bit better as you always pass around copies but if a struct is mutable then it's still fundamentally impure and assists in permeating impurity; at least in an impure setting; say you have a method that has a local variable that is a struct type, then mutating this should be no major issue but if, on the other hand, this struct is not local but ambient in the object, then mutating it will affect purity of the object.

     

    I believe D is working towards supporting notions of purity and the same with C# or maybe generally .Net in that I saw some special contract attributes for this somewhere (maybe).

     

    It's interesting to think about having types be pure but also having a special purity constraint on types which the type-checker can enforce. This is the inverse of what Haskell does: everything is pure unless it's not - and then you get trapped in the IO monad. It would be quite nice to have a similar formalism, if reversed, for .Net, where you could express Pure<T>.

     

    This would of course be a very special type, requiring compiler magic, depending on the power of the language itself; e.g. C# with a step in a multi-step compilation process for doing expression tree verification of static invariants such as purity; well, that's an advanced topic: allowing the programmer to extend the type-system/checker with arbitrary invariants; in a way we can think of contracts in this way too (it's just that many invariants can't be statically verified; but using types with more associated meaning would seem more powerful; somewhat like dependent typing perhaps.)

     

    [1] Not strange in a pragmatic sense (language evolution takes time) but weird in an idiological sense (absent a notion of time, one could argue about imperfections such as unnecessary non-uniformity between structs and classes; on the other hand[3])

    [2] Not a pun

    [3]Talk is cheap

    On the other hand it is strange[1] that it's not possible to express that a struct (such as Tuple) conforms to an interface (such as IComparable<T>).

    That's not true. Structs can implement interfaces just fine.

  • User profile image
    exoteric

    Sven Groot said:
    exoteric said:
    *snip*

    That's not true. Structs can implement interfaces just fine.

    Thanks! I tried this a couple of weeks ago but misread the compiler output.

    I would kick my own behind for this mistake but anatomy forbids it.

  • User profile image
    Dodo

    exoteric said:
    Ion Todirel said:
    *snip*

    To illustrate

    public struct STuple<a>
    {
        private readonly a x;
        public a Some
        {
            get { return x; }
        }
        public a this[int index]
        {
            get
            {
                if (index != 0)
                    throw new IndexOutOfRangeException();
                else
                    return x;
            }
        }
        public IEnumerator<a> GetEnumerator()
        {
            yield return Some;
        }
        public static int Index
        {
            get { return 0; }
        }
        public static int Length
        {
            get { return Index + 1; }
        }
        public STuple(a a)
        {
            x = a;
        }
    }
    public struct STuple<a, b>
    {
        private readonly a x;
        private readonly STuple<b> s;
        public a Some
        {
            get { return x; }
        }
        public STuple<b> Rest
        {
            get { return s; }
        }
        public dynamic this[int index]
        {
            get
            {
                if (index > Index || index < 0)
                    throw new IndexOutOfRangeException();
                else
                    return index == Index
                        ? Some as dynamic
                        : Rest.Some as dynamic;
            }
        }
        public IEnumerator<dynamic> GetEnumerator()
        {
            yield return Some;
            yield return Rest.Some;
        }
        public static int Index
        {
            // C# forbids: (Rest.Index + 1)
            get { return 1; }
        }
        public static int Length
        {
            get { return Index + 1; }
        }
        public STuple(a a, b b)
        {
            x = a;
            s = new STuple<b>(b);
        }
    }

    Example

    var a = new STuple<int>(3);
    var b = new STuple<int,int>(1,2);
    foreach (var x in a)
        Console.WriteLine(x);
    foreach (object x in b)
        Console.WriteLine(x);
    Console.ReadKey();
    

    If we could somehow express a version of GetEnumerator that only applies to a homogeneous (s)tuple, meaning (s)tuple where all type parameters are equal, then there would be no need for a dynamic formulation, esp. as this is statically known.

    public static class STupleExtensions
    {
        public static IEnumerator<a> GetEnumerator<a>(this STuple<a, a> s)
        {
            yield return s.Some;
            yield return s.Rest.Some;
        }
    }
    

    I realize though that this kind of trickery is probably not very high on any wishlist heh

    I'd want that, too. Smiley

  • User profile image
    exoteric

    Dodo said:
    exoteric said:
    *snip*

    I'd want that, too. Smiley

    Inspired by the XHTML thread, this idea popped up; not new by any means but very much missing in action. First importing the members of a static class (Java people know this as static import; SML people as open; VB.NET people as something else)

     

    public double Ex(double x)
    {
        using Math;
        var z = 1/Sinh(x);
        ...
        return z3;
    }

     

    Next: importing the members of an enum

     

    public enum HtmlChar : ushort
    {
        nbsp = '\u00A0'
        ...
    }
    ...
    public void Output()
    {
        using HtmlChar;
        var e = new XElement("p", ..., nbsp, ...);
        ...
        e.Save(...);
    }

     

    So two very different and very common scenarios covered by this (double-) feature.

     

    [edit:] ushort does not work for Unicode in general, so have to switch to strings, which rules out enums

  • User profile image
    Frank Hileman

    exoteric said:
    Frank Hileman said:
    *snip*

    There is some elegance as well: auto-boxing and unboxing of values. <edit:wrong>On the other hand it is strange[1] that it's not possible to express that a struct (such as Tuple) conforms to an interface (such as IComparable<T>). Being a struct offsets you to a second-class[2] citizenship, stripped of priviledges such as interface inheritance.</edit:wrong>

     

    Constness is really about purity as immutable objects lead to purity. Structs render mutability a tiny bit better as you always pass around copies but if a struct is mutable then it's still fundamentally impure and assists in permeating impurity; at least in an impure setting; say you have a method that has a local variable that is a struct type, then mutating this should be no major issue but if, on the other hand, this struct is not local but ambient in the object, then mutating it will affect purity of the object.

     

    I believe D is working towards supporting notions of purity and the same with C# or maybe generally .Net in that I saw some special contract attributes for this somewhere (maybe).

     

    It's interesting to think about having types be pure but also having a special purity constraint on types which the type-checker can enforce. This is the inverse of what Haskell does: everything is pure unless it's not - and then you get trapped in the IO monad. It would be quite nice to have a similar formalism, if reversed, for .Net, where you could express Pure<T>.

     

    This would of course be a very special type, requiring compiler magic, depending on the power of the language itself; e.g. C# with a step in a multi-step compilation process for doing expression tree verification of static invariants such as purity; well, that's an advanced topic: allowing the programmer to extend the type-system/checker with arbitrary invariants; in a way we can think of contracts in this way too (it's just that many invariants can't be statically verified; but using types with more associated meaning would seem more powerful; somewhat like dependent typing perhaps.)

     

    [1] Not strange in a pragmatic sense (language evolution takes time) but weird in an idiological sense (absent a notion of time, one could argue about imperfections such as unnecessary non-uniformity between structs and classes; on the other hand[3])

    [2] Not a pun

    [3]Talk is cheap

    Constness (knowing if an object can be modified by a method) might be about purity if you are thinking about functional languages and concurrency. I simply find value semantics easier to reason with and work with, whether or not I am using a functional language or concurrency. It feels natural.

     

    If you make a heap allocated data type (class in C#) immutable, it starts to acquire value semantics. But you still need to implement a lot of boilerplate code (Equals, IEquatable, operator == !=, GetHashcode etc), this code is a waste of time, and it is different from the boilerplate code you need for a stack allocated data type (struct in C#). The choice of value semantics or reference semantics should be independent of the allocation technique. 

     

    Ideally, we can change from heap to stack based allocation without changing the data type implementation or usage. C# is probably permanently broken. But anything to move in that direction, and reduce the amount of code bloat, would be helpful.

  • User profile image
    SlackmasterK

    I think the biggest and most important change in newer versions of the framework is simply this:

     

    Companies should upgrade to it.

     

    My .NET 3 - 4 skills are going to waste, except on my hobby projects. My previous job is just now starting to upgrade to .NET 2.0.

  • User profile image
    GrantB

    Not really sure about these but...

    (1) Clojure like pure/persistent data structures and STM.

    (2) Go like type equivalence.

    (3) Erlang like lightweight processes, perhaps using heap allocated stack frames (c.f. Second Life marshalling).

     

  • User profile image
    exoteric

    GrantB said:

    Not really sure about these but...

    (1) Clojure like pure/persistent data structures and STM.

    (2) Go like type equivalence.

    (3) Erlang like lightweight processes, perhaps using heap allocated stack frames (c.f. Second Life marshalling).

     

    There doesn't appear to be anything special about Go's notion of type equivalence beyond structural typing. C# has dynamic now, not sure the good folks want to go beyond that because dynamic allows you to apply the same programming pattern but in a less type-safe way. Another idea is to be able to coerce a type that structurally matches a different type into that type - a sort of structural cast.

     

    Love the idea behind persistent data structures.

  • User profile image
    Spongman

    exoteric said:

    Unnullability a la

        public struct Unnullable<T> where T : class
        {
            public Unnullable(T x)
            {
                if (x == null)
                    throw new NullReferenceException();
                item = x;
            }
            public T Item
            {
                get
                {
                    return item;
                }
            }
            private readonly T item;
        }
    

    and used as such

        class Foo
        {
            int Bar = 3;
        }
        class Program
        {
            static void Main(string[] args)
            {
                var ufoo = new Unnullable<Foo>(new Foo());
                Console.WriteLine(ufoo.Item);
                Unnullable<Foo> baz; // error
                Unnullable<Foo> bax = null; // error
                Unnullable<Foo> box = (Foo)null; // error
                Console.ReadKey();
            }
        }
    

    with built-in compiler support so we can simply write

    var ufoo = new Foo!(); // type of ufoo is Foo! => Unnullable<Foo> 
    Console.WriteLine(ufoo.bar);

    Even without compiler support it will help catch nullness errors because in this case the compiler just translates ! to Unnullable - a kind of dual of ? which translates to Nullable. And with compiler support you may not even need to explicitly implement as Unnullable<T> although it will probably make the implementation easier.

     

    And of course unnullable classes - where by default the class is unnullable.

    mod up Unnullablfe<T> (although I'd prefer NonNullable<T>). It should be usable in all places types are usable today and the framework should make full use of it. This would obviously require a CLR rev. Languages that support it should mark their assemblies appropriately, those that don't have the implicit casts/expections added for them by the jit.

  • User profile image
    exoteric

    piersh said:
    exoteric said:
    *snip*

    mod up Unnullablfe<T> (although I'd prefer NonNullable<T>). It should be usable in all places types are usable today and the framework should make full use of it. This would obviously require a CLR rev. Languages that support it should mark their assemblies appropriately, those that don't have the implicit casts/expections added for them by the jit.

    Nonnullable<T> is not bad, it's close to the latin Nonnullus which looks and sounds beautiful. That said, personally speaking, there is an strange eerie funny attraction to Unnullable<T>. Anyway, that's naming...

     

    Actually for non-nullability, we'd probably want two things

    1. definition-site non-nullability annotation
    2. use-site non-nullability annotation

    And preferably we want these to be low-impact in terms of syntax.

     

    Example 1: use-site non-nullability (ejecting null from the domain of Tuple<int,int>)

     

    Tuple<int,int>! thouShaltNull = Tuple.Create(10,20);

     

    Example 2: definition-site non-nullability (giving birth to a new type that is non-nullable)

     

    public class Tuple<int,int>!
    {
        ...
    }

     

    Example 3: use-site nullability of a reference type which is born non-nullable

     

    UnnullableTuple<int,int>? thouMayNull = ...;

     

    It will be forbidden to construct a combination such as

     

    Unnullable<Nullable<Val>> ... // error
    Nullable<Unnullable<Ref>> ... // error

     

    where Val is some value-type (non-nullable) and Ref is some reference type (nullable); so that the inner type is born (un-)nullable and at use-site you create a double negation.

     

    Same as

     

    Val?! ... // error
    Ref!? ... // error

     

    It is also forbidden to create unnnullable+unnullable and nullable+nullable combinations.

  • User profile image
    ramooon

    exoteric said:
    Ion Todirel said:
    *snip*

    To illustrate

    public struct STuple<a>
    {
        private readonly a x;
        public a Some
        {
            get { return x; }
        }
        public a this[int index]
        {
            get
            {
                if (index != 0)
                    throw new IndexOutOfRangeException();
                else
                    return x;
            }
        }
        public IEnumerator<a> GetEnumerator()
        {
            yield return Some;
        }
        public static int Index
        {
            get { return 0; }
        }
        public static int Length
        {
            get { return Index + 1; }
        }
        public STuple(a a)
        {
            x = a;
        }
    }
    public struct STuple<a, b>
    {
        private readonly a x;
        private readonly STuple<b> s;
        public a Some
        {
            get { return x; }
        }
        public STuple<b> Rest
        {
            get { return s; }
        }
        public dynamic this[int index]
        {
            get
            {
                if (index > Index || index < 0)
                    throw new IndexOutOfRangeException();
                else
                    return index == Index
                        ? Some as dynamic
                        : Rest.Some as dynamic;
            }
        }
        public IEnumerator<dynamic> GetEnumerator()
        {
            yield return Some;
            yield return Rest.Some;
        }
        public static int Index
        {
            // C# forbids: (Rest.Index + 1)
            get { return 1; }
        }
        public static int Length
        {
            get { return Index + 1; }
        }
        public STuple(a a, b b)
        {
            x = a;
            s = new STuple<b>(b);
        }
    }

    Example

    var a = new STuple<int>(3);
    var b = new STuple<int,int>(1,2);
    foreach (var x in a)
        Console.WriteLine(x);
    foreach (object x in b)
        Console.WriteLine(x);
    Console.ReadKey();
    

    If we could somehow express a version of GetEnumerator that only applies to a homogeneous (s)tuple, meaning (s)tuple where all type parameters are equal, then there would be no need for a dynamic formulation, esp. as this is statically known.

    public static class STupleExtensions
    {
        public static IEnumerator<a> GetEnumerator<a>(this STuple<a, a> s)
        {
            yield return s.Some;
            yield return s.Rest.Some;
        }
    }
    

    I realize though that this kind of trickery is probably not very high on any wishlist heh

    I would love to see a way to extend types beyond that awkward "first-parameter-with-this-modifier" trick.

    For example this natural syntax would be awesome:

     

    // 'class', 'struct', 'interface' or 'enum' keywords
    // are useless here since the type already exists
    public extension TypeToExtend
    {	
         // 'public' modifier is useless here, as in any interface declaration
         void ExtensionMethod()
         {
              // the 'this' keyword is available here
              ...
         }
    
         static void StaticExtensionMethod()
         {
              // the 'this' keyword is NOT available here, as in any static method
              ...
         }
    
         void ExtensionProperty { get; set; }
    }
    

     

     

     

    As you can see it would allow "extension properties" and "extension static methods".

    You could even have "extension constructors", "extension events" and so on...

    Everything you could imagine to extend !

     

  • User profile image
    exoteric

    ramooon said:
    exoteric said:
    *snip*

    I would love to see a way to extend types beyond that awkward "first-parameter-with-this-modifier" trick.

    For example this natural syntax would be awesome:

     

    // 'class', 'struct', 'interface' or 'enum' keywords
    // are useless here since the type already exists
    public extension TypeToExtend
    {	
         // 'public' modifier is useless here, as in any interface declaration
         void ExtensionMethod()
         {
              // the 'this' keyword is available here
              ...
         }
    
         static void StaticExtensionMethod()
         {
              // the 'this' keyword is NOT available here, as in any static method
              ...
         }
    
         void ExtensionProperty { get; set; }
    }
    

     

     

     

    As you can see it would allow "extension properties" and "extension static methods".

    You could even have "extension constructors", "extension events" and so on...

    Everything you could imagine to extend !

     

    Interesting idea. It looks like a more complete/holistic/uniform approach to type extension, kudos. It is reminiscent of partial classes, except not exclusive for classes. Now I wonder: if you have a partial class A and another partial class B in two distinct namespaces and say you have a simple console program and the console program imports partial class A; will partial class B then also implicitly be used or only if you explicitly import that namespace? In the latter case the partial class construct looks pretty darned close to what you want, except partial to classes, so to speak. Hindsight is great.

     

    As for public/private, private is probably a sign of imperativeness because in an imperative setting you want to be careful about who's modifying your object using your special helper methods whereas when constructing new objects it's not really that big of an issue and this default looks wrong for a mostly-declarative world (or functional if you will). This will also save lots of code having to explicitly declare public all over. Well... too late for C#, that ship sailed long ago.

Comments closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums, or Contact Us and let us know.