Hacker News new | past | comments | ask | show | jobs | submit login

C# programmer for a couple years, and I think C# is OK (it's definitely way ahead of Java or C++) but I've definitely got a big list of things I don't like about it. The top of it reads:

- Events and properties aren't first-class, which is lame. I can't even easily get the "get" or "set" method of a property without either using reflection or making a wrapper lambda.

- No syntax sugar for tuples.

- No syntax sugar for destructuring anything. Come on now.

- The type system has big holes. For example, I still can't specify class Something<T> where T : new(T) (i.e. where a copy constructor exists on T.) And I can't specify class Something<T> where T : /* is a numeric type */.

- It would be nice if there were type inference on more things, like property and field types.

- All reference types are nullable which sucks.




This is a good list. The lack of decent sugar for tuples makes them very annoying to work with and situations demanding two or more dependent return values are the one place where my code looks nasty and is difficult to follow (unless I create a class specifically for the return type, which I usually end up doing).

By numeric type do you mean a type implementing numeric operations? I agree, it's weird they haven't just whacked an interface on that.

And when are we getting an "unless"? It's way more readable than "if (!(some complex condition))".

Oh and null coalescing with member support. "y = x != null ? x.prop : value" is way too verbose.


> The lack of decent sugar for tuples makes them very annoying to work with and situations demanding two or more dependent return values are the one place where my code looks nasty and is difficult to follow (unless I create a class specifically for the return type, which I usually end up doing).

At least you have the option of out params. I have to use Java every day and the only real option is return classes.


I don't know if I misunderstanding you, but you can indeed specify class Something<T> where T : new Check this out: http://msdn.microsoft.com/en-us/library/d5x73970.aspx

And about numerical types, I agree that would be great to have a base class "Number" for double, int, etc. But meanwhile you can use this trick: http://stackoverflow.com/questions/3329576/generic-constrain...


Right now you can only specify that a type must have a paramerterless public constructor. He or she wants to be a le to specify (presumably) arbitrary constructors (or at least a copy constructor).


Most of your issues are addressed by the Base Class Library (BCL), which is provided by the runtime itself. You cannot use C# without the BCL, so why evaluate it without the BCL? How do the following sit with you?

- Events, i.e. the observer pattern, are indeed supported first class by way of the `event` keyword and BCL `Delegate` type. And the whole point of properties is to be syntactic sugar to hide implementation details by surfacing state accessors with field-like mechanics. If you need a quick and easy way to reference a "getter method", you're breaking the abstraction and shouldn't use properties. That's the trade off.

- The BCL provides multiple generic, high-performance `Tuple` types.

- Destructing. Memory management is handled by the GC, so what would destructing even mean? The `using` keyword along with BCL type `IDisposable` provides a very usable mechanism for releasing non-memory/unmanaged/OS resources.

- This is mostly valid. That said, `ICloneable` can get you most of the way w.r.t. the copy ctor. As far as the numeric generic, one is required to make do with type-specificity and method overrides, since the numeric types were written without generics in mind. Or you can implement your own numeric type system. Do that once and you can write numeric generics to your heart's desire.

- How could this work with auto-properties?

- Trivial to implement a `NonNull<T> where T : class`. But because of other language constructs (`??` operator) idiomatically `null` references are not considered the end of the world. Design by contract support in the BCL `Contract` type alleviates this as well.

edit: expanded property method explanation.


He said destructuring, not destructing. Like so:

   int a, b;
   (a, b) = function_returning_array();


Regarding events: It's a common pattern to pass a function into a method as a callback to do an inversion-of-control kind of thing, like "on error, call this." It would be natural to pass an event with the semantics "on error, fire this event." But there is no way to pass an event. You can imagine similar situations with properties.


Your list basically boils down to "C# isn't <insert favorite language>". Which is fair of course, but most of your list wouldn't really make sense in C#.


That's just not true.

All the suggestions on the list make sense, and many like them have been added over teh past few years. To me it seems that all of them except the 'reference types that are not nullable' one could be easily added without breaking backward compatibility.

In fact, I wouldn't be amazed if a C# 6 has sugar for tuples and destructuring assignments and the likes. It matches the language well (already got a type-inferencing compiler, already on the road to incorporating increasingly many functional programming ideas).

And, well, in code you can already say

    var george = new Person();
But in property and field definitions, you still have to say

    Person george = new Person();
How is allowing "var" there a turning "C# into a different language"? Nearly the entire list the GP mentions are fixes on this level of complexity.

The only reason I see for not doing things like this is to avoid becoming the next C++, in which there's just too many features and things to understand.


What you suggest could work, but I'm not sure how useful that would be in the end when you still have to declare the type for fields initialized in the constructor. The var keyword inside methods covers most cases of using variables. A "var" keyword on the field level would cover less than half of the cases. Plus, you'd have to add a new keyword to do it as "variable" doesn't quite fit the meaning. Just not sure how useful that is.

sugared tuples and destructuring doesn't really fit. You'd have to make special case syntax for it and it would just feel bolted on to the language. Plus, tuples lose their usefulness if you have to declare its type to pass it between methods.

Though his first point about getters and setters does make sense, I didn't quite comprehend it the first time around.


You'd have to make special case syntax for it and it would just feel bolted on to the language. Plus, tuples lose their usefulness if you have to declare its type to pass it between methods.

I think it could be OK even without return type inference on methods. Imagine you could type this:

  (int, bool) TryParse(string str) {
     // do stuff
     return (num, success);
  }
That would be clean enough.


I think you might be right about that one. That does look rather elegant. I was initially skeptical about creating a totally new language construct to create inline tuples, as (num, success) looks like it needs a new in front of it, which ruins the pattern of assignment for destructuring.

But once you get over that mental hump of seeing a new in front, it really starts to make a lot of sense. A tuple could be considered a value type and treated similarly to int or string literals. Very cool.


How would you access the return value object? Given obj is (int, bool), obj.Key and obj.Value? Or obj[0] and obj[1]?


Why would sugared destructuring not make sense in C#? Or first class events and delegates?


Destructuring just doesn't fit with the current language syntax. There are no copy constructors in C#, so something like [a, [b, c]] = [1, [2, 3]] makes no sense syntactically. In languages where declaring objects don't require a new, this syntax follows naturally.

For the simple case of say, destructuring a tuple, that could work well: a, b = ReturnsATuple(). But anything more general would just seem tacked onto the language.

But then again, tuples don't really fit well in C# either! Tuples are only useful if you don't have to declare their types, ever. Without full type inference, nothing is saved by using tuples over, say, an inline object.

I don't understand the significance of first class events, so I can't really comment on that. And as far as I know, delegates are first class now with the inclusion of lambdas.


A good list, which can be extended. Just recently, for example, I came across the unpleasant fact that interfaces in C# cannot be nested (in fact, a C# interface is not allowed to define any nested types). Inconvenient, breaks encapsulation, and does not seem to have a good technical reason for it.

And yet, working with C# is joyful.


Did you have a look at Scala?

- There are only properties, no fields or other stuff. This means you can replace a method with a constant easily, or add your own setter to a mutable property later without breaking source or binary compatibility.

- Tuples: (1, "Foo", 42.0)

- val (a,b) = (1,2). Also works with regexes, case classes, ... basically everything which has an `unapply` method.

- class Something[T : Numeric]

- Type inference everywhere, with the exception of method parameters (and recursive methods).

It also has one of the most powerful type systems, traits, everything-is-an-object, higher-order functions, higher-kinded types.

Caveat: Runs on the JVM. The .Net port hasn't been officially released, but is planned for the next release.

There is an introduction for C# developers, if you are interested: http://docs.scala-lang.org/tutorials/scala-for-csharp-progra...




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: