Coffeehouse Thread

49 posts

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

C#'s biggest mistake

Back to Forum: Coffeehouse
  • User profile image
    vesuvius

    As languages are evolved, it is clear that compromises (and or mistakes) are made along the way. C# now seems a mature language, with a huge set of API's available, and almost a lack of now stuff to be added that revolutionises the language.

    What would you say is the biggest error they made, in either including, implementing or omitting a feature?

  • User profile image
    felix9
  • User profile image
    Dexter

    I think the biggest mistake was the initial release of C# without generics. The traces of the old, non-generic, interfaces, delegates, collections etc. are visible to this day in both user written code and the .NET Framework library.

    Of course, this isn't stricly about C# as the runtime itself didn't support generics at that time...

  • User profile image
    W3bbo

    , Dexter wrote

    I think the biggest mistake was the initial release of C# without generics. The traces of the old, non-generic, interfaces, delegates, collections etc. are visible to this day in both user written code and the .NET Framework library.

    Of course, this isn't stricly about C# as the runtime itself didn't support generics at that time...

    I don't know, the non-generic things like ArrayList and non-typed collection interfaces are useful, so the only problem is the inconsistency in naming (e.g. why isn't it ArrayList<T> instead of List<T> ?) and also namespaces (it would be better if the generic collection types were under System.Collections rather than System.Collections.Generics).

  • User profile image
    Dexter

    Yes, the non generic collections can be useful sometimes but in many (all?) cases you can achieve the same results by using a generic collection with an object type argument (List<object>  for example).

    Now, the existence of the non generic collections is not a big issue. The problem is with framework APIs that are still using non generic interfaces (see for example the PropertyDescriptorCollection in System.ComponentModel which implements IList & co.)

    PS: AFAIK "Array" was dropped from List<T> because it unnecessarily exposes an implementation detail (a list is implemented by using an array).

  • User profile image
    W3bbo

    Yes, the non generic collections can be useful sometimes but in many (all?) cases you can achieve the same results by using a generic collection with an object type argument (List<object>  for example).

    Now, the existence of the non generic collections is not a big issue. The problem is with framework APIs that are still using non generic interfaces (see for example the PropertyDescriptorCollection in System.ComponentModel which implements IList & co.)

    I'd like to see .DataSource properties (typed as Object) replaced with a more stronger-typed alternative. The documentation lists what interfaces are accepted, so why not put that in the code?

  • User profile image
    Dexter

    They did so in WPF. The ItemsSource property of the ItemsControl is IEnumerable instead of object Smiley.

  • User profile image
    Bass

    , Dexter wrote

    Yes, the non generic collections can be useful sometimes but in many (all?) cases you can achieve the same results by using a generic collection with an object type argument (List<object>  for example).

    Now, the existence of the non generic collections is not a big issue. The problem is with framework APIs that are still using non generic interfaces (see for example the PropertyDescriptorCollection in System.ComponentModel which implements IList & co.)

    PS: AFAIK "Array" was dropped from List<T> because it unnecessarily exposes an implementation detail (a list is implemented by using an array).

    How would you explain LinkedList<T>?

  • User profile image
    W3bbo

    , Bass wrote

    *snip*

    How would you explain LinkedList<T>?

    I believe that class/struct names should reflect their implementation concept/theory, but that interface types shouldn't. That isn't the same thing as "exposing implementation details" like fields.

  • User profile image
    Dexter

    Well, you cannot have 2 List<T>s, right? Anyway, that's what I read once one some blog, a long time ago.

    If you ask me, this "exposes implementation detail" is a bit pompous. They also changed Hashtable to Dictionary but it's not like you can hide the fact that the Dictionary uses a hashtable internally. You have to document the fact that it requires GetHashCode to work properly, so much for hiding implementation details...

  • User profile image
    Bass

    , W3bbo wrote

    *snip*

    I believe that class/struct names should reflect their implementation concept/theory, but that interface types shouldn't. That isn't the same thing as "exposing implementation details" like fields.

    I don't really agree with hiding implementation details for collections either. It's very important for the consumer of the collection to know if a list uses a linked list or array, because the difference in algorithmic complexity between the data structure operations could mean order of magnitude(s) worse performance depending on how they are used.

  • User profile image
    Bass

    Generally speaking C# is a good language. I don't know what would be the worst things, but this is what I don't like.

    • More of the .NET thing, but the prefixing of the interfaces with "I". Just looks ugly to me, and I think it discourges use of interfaces when they really should be used (I don't see IList used so often, even though "List" is an implementation I've seen methods that only accept it).
    • As we were talking above, I think the collections in .NET are generally poorly designed.
    • The C++ syntax for class inhertence. It makes sense in C++ because there is no language distinction between interface and class. They should have taken Java's syntax for this.
    • Multiple language features that do similar (or even the same thing). One example: lambda vs anon functions.
    • LINQ-to-Objects. Some people seem to thing it looks fancy in code (I guess?), but I don't think it makes the code any clearer then a simple foreach loop (which tends to be faster anyway). See above also.
  • User profile image
    felix9

    personally I want:

    array on stack and array embedded/inlined in struct
    indexed property
    event assigning in the object initializer block
    more flexible and powerful generics type parameter constraints, like valuetypes and math operators

  • User profile image
    BitFlipper

    I think the way they implemented extension methods is too limited, convoluted and broken. There is a much cleaner and easier way. They should have used the same concept as a "partial" class, and implemented extension methods like this:

    public extension class SomeExistingClass
    {
        // Add whatever instance or static methods you want
        // Add any properties you want
        // You can't add any new fields though...results in compiler error
    }

    The compiler should then impose extension-specific limitations, like the fact that you can't add new fields, but you are now free to add new methods and properties using the exact same syntax that we are already familiar with.

    The advantage here is that there is nothing new that the developer needs to learn other than how to spell "extension". No more weird static methods with the first "this" parameter, full support for properties and static methods, etc.

    EDIT: Oh, and for value types, the "this" parameter should be a ref to the original struct, not a copy of it. Yes, there really are cases where you want to change just one or two values in a struct for performance reasons (see the XNA Matrix class, which consists of 64 bytes and is used in tight loops in 3D games. The existing extension mechanism forces two full copies of a value type if you need to return a modified version of it).

    CLARIFICATION: It seems some people think I'm implying that the class you are extending has to be within the same namespace as the original class. This is not true and this is never what I proposed. The class can be in any other namespace, just like extension methods right now can be in any other namespace. If there are name collisions, you would need to qualify the class you are extending exactly like you would need to qualify it right now with the existing extension mechanism.

    Also, I'm not proposing that the compiler use the exact same restrictions as that of a "partial" class. It is merely a way to demonstrate that there is precedent for similar syntax elsewhere. An extension class will come with its own set of restrictions, and the compiler will enforce those  restrictions. For instance, you would not be able to add new fields etc.

  • User profile image
    littleguru

    I personally don't like how nullable structs are exposed through the language. I always got the feeling as if the feature is only half-done Smiley

    But other than that C# is one of my favorite languages!

  • User profile image
    W3bbo

    , Bass wrote

    Generally speaking C# is a good language. I don't know what would be the worst things, but this is what I don't like.

    • More of the .NET thing, but the prefixing of the interfaces with "I". Just looks ugly to me, and I think it discourges use of interfaces when they really should be used (I don't see IList used so often, even though "List" is an implementation I've seen methods that only accept it).
    • As we were talking above, I think the collections in .NET are generally poorly designed.
    • The C++ syntax for class inhertence. It makes sense in C++ because there is no language distinction between interface and class. They should have taken Java's syntax for this.
    • Multiple language features that do similar (or even the same thing). One example: lambda vs anon functions.
    • LINQ-to-Objects. Some people seem to thing it looks fancy in code (I guess?), but I don't think it makes the code any clearer then a simple foreach loop (which tends to be faster anyway). See above also.

    The IInterface thing is from COM, but I prefer it because often you have types and related interfaces that should have the same name, but without the I prefix you'd get a collision. It is interesting how it's the single exception from the "strictly no hungarian" rule in .NET.

    It also makes it possible to glance at a type definition and see what types it extends vs what interfaces it implements.

    I wouldn't say they do the same thing: Lamba functions are an application of anonymous methods (and as far as CIL is concerned, they're the same thing). It's like saying we shouldn't have verbatim "@" strings because you can express their contents as regular strings.

    Linq-to-Objects is meant for complicated in-memory object graphs. Outside of data access (which we've got Linq-to-Sql for anyway) I can't see many applications. Maybe in massive data visualisation, but I've seen more people abuse it or make something overly complicated.

    , felix9 wrote

    personally I want:

    array on stack and array embedded/inlined in struct
    indexed property
    event assigning in the object initializer block
    more flexible and powerful generics type parameter constraints, like valuetypes and math operators

    You can already do array-on-stack using the stackalloc keyword and struct arrays with the fixed keyword. The only catch is it's got to be within an unsafe context. For example:

    unsafe struct Foo {
        public fixed char[128];
        public static Bar() {
            int* baz = stackalloc int[ 512 ]; // create a 512-element sized array on the stack, it does not need to be freed
        }
    }

    indexed properties... they already exist with the 'this' property, so what you're actually after is named indexed properties. The thing is that such a system would conflict with the current 'this' property (e.g. what happens if a named-indexed-property returns an object with a 'this' property?).

    , BitFlipper wrote

    I think the way they implemented extension methods is too limited, convoluted and broken. There is a much cleaner and easier way. They should have used the same concept as a "partial" class, and implemented extension methods like this

    I agree, but that approach doesn't lend itself to making lots of extensions for a large number of types, as you have to create a new type for each of them (even if you're only adding a single new member).

    An advantage of the 'extension class' approach is you can now have extension properties (without any weird convulted syntax).

    The language designers could add both approaches, but then they'd get shot down for language bloat. I guess we're stuck.

     

  • User profile image
    exoteric

    No's:

    No opt-in policy for nullness (Maybe<T>), except for structs via Nullable<T>
    No opt-in policy for mutability (classes, structs)
    No recursive enumerations (datatype constructors) or pattern-matching
    No generic numerics
    No kind-system

    Hmm's:

    Slow linq to objects, unsuitable for fundamentalists (iterators don't mesh well with recursive use/structures.)
    Partial classes and extension methods - not as holistically designed as one might wish

    Symptoms of a 10 year old language and runtime.

    Dispite all this it's still a great language.

    PS - language doesn't need runtime just to support generics - look at Java. Bracha et al made generics via type-erasure (don't like it due to performance, but it shows its possible.)

  • User profile image
    BitFlipper

    Well I wonder how feasible it would be deprecate some of the older features? And when I say "deprecate", I mean not just a warning, but completely removing it from the language.

    I mean, it isn't as if your current projects automatically starts using the latest .Net version without your control. You usually have to tweak a project anyway when you switch .Net versions, so I don't think it is such a bad thing.

    This will ensure that the language doesn't get too bloated just for the sake of backwards compatibility when there are new/better ways to do the same thing.

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.