For the stdlib there is no one single problem it's death by a thousand cuts in a lot of various ways. Over reliance on inheritance for polymorphism which limits composability in a lot of ways. Too little use of interfaces.
Some of this seems like it's due to backwards compatibility concerns but it definitely degrades the developer experience with the language. Which is a shame because c# has a lot to offer.
I was once told that a lot of the original libs were effectively ported from C++ libs by C++ devs in a hurry. There are nuget packages with decent data structure / collections missing from the core BCL.
Interfaces like IEnumerable<T>, IComparable<T> and IEquatable<T> I find to be extremely useful and if you're following interface segregation principle and not chucking round the actual concrete implementations. I concede though that the BCL would be richer if one didn't have to think about this stuff too much.
I guess there's enough experienced C# devs around to know how to avoid those pitfalls. As the BCL is shrunk I expect it will be easier to substitute any structures your not happy with, with alternatives.
Some of C#'s interfaces are simple and well designed, but the OOP model used is kind of weak for composition of them. For example, one would often like an IIndexable interface to cover both arrays and lists, or an numeric interface for which we can perform common operations over any number type. Without the ability to extend existing implementations with new interfaces, we're stuck using various patterns and wrappers to get the abstraction we need.
I was a C# developer for about 6 years before I got tired of the same old problems and decided it's not for me. I still use it occasionally when required, but not if other options are available.
I’ve thought about this.
To be useful, an IIndexable would need get and set methods for the index, and a Length/Count property. You would need to explicitly implement it on something like the array class since you wouldn’t want to lose the semantic difference between Length (O(1)) and Count (O(n)).
But, the existence of Func<T, TResult> and Action<T1, T2> would largely obsolete the utility of such and interface.
Let xs be an “indexable” object of T (e.g. T[] or List<T>). Then any method that expects to only access an object could just accept lambda of type int -> T. So, you’d just pass it
n => xs[n].
Similarly, methods that expect to mutate the object could take a lambda of type (int, T) -> (). So would just pass something like (n, x) => xs[n] = x.
This is nicer because it makes explicit what the method will do to the indexable. I guess the problem is that it's not discoverable.
I think you are absolutely right. While the reflection is available (and the documentation, in general, is not at all bad), discoverability is still weak.So the
bool Int32.TryParse(string value, out number)
method would probably nowadays be better done as Int? Int32.TryParse(string value)
Similarly, WinForms has loads of different events of different types with individual delegates created for them. Nowadays you'd use Func and Action instead.A better pattern used in say, F#, would be to return the tuple of <bool, T>, which could handle reference types and value types uniformly unlike Nullable. That won't slide in C# though as there's no syntactic sugar for tuples, and calling .Item1, .Item2 is too "inelegant" for the regular programmer.
For now though, the bool Try_(_, out _ _) is still the preferred method by most.
Func and Action are certainly useful, but sometimes having a named delegate type is still preferable because you can capture the purpose of the delegate in it's name, rather than resorting to doc comments nobody is going to read anyway.
I agree that it would be nice if C# checked that you dealt with the null case of the return - Resharper will happily warn me if I haven't, but it would be nice if the base compiler did. Maybe in the future!
The point is that it is not necessarily correct to conflate the nullability of the parse with the correctness of the parse. If I wanted to parse a string into a Foo, null might be a valid value for a successful parse to return, say because the rule is that the string "(null)" maps to a null Foo.
I have implemented TryParse methods on many reference types with exactly these semantics - object on success, null on failure (often with details logged at DEBUG).
Also, I'm constantly frustrated how many core libs freak the heck out over a null string vs. an empty string. Obviously there are places to distinguish those, but if I'm trying to create a nullable int out of the text that is not one of them.
public static class StringExtensions
{
public static Int32? ParseAsNullableInt32(this String self, Int32? fallback = null)
{
Int32 result;
return Int32.TryParse(self, out result) ? result : fallback;
}
}In the case of the XML Serializer, that means that if I declare a class with Nullable<int> Foo {get;set;}
and
<Foo />
appears in the XML body, then it blows up. The WebForms stuff is similarly pathetic about empty strings. There is no useful distinction between empty strings and nulls when we're talking about dates or numbers or something like that, so throwing an exception in this case is just plain wrong. It's not even protecting backwards compatibility because pre-2.0 C# didn't even have nullable ints.They've also done a terrible job of making a first class Windows UI library for .NET; WinForms was always clunky and limited in the subset of MFC/GDI it exposed; WPF was too radical and didn't make sufficient use of the underlying native capabilities of Windows - and the WinRT story has been confused from day 1.
Obviously if you are only going to ever develop for iOS then going with Swift could make sense but then it seems that Xamarin would've never really have been an option anyhow, irrelevant of cost.
Of course, this may have changed.
In my current project (a video game), the core library is a PCL - it contains data structures and the interfaces and abstract classes that content (mods as well as the base game) must fulfill. I have a "desktop" library that's a normal .NET 4.5 class library that contains stuff like "load your config data from files, include the runtime-compilation mod system", and I have runner projects--text-mode via curses for now, eventually graphical post-prototype--for MacOS, Windows, and Linux[1]. I use configurations (not platforms, leave everything as AnyCPU unless you want to hate your life) to provide preprocessor flags for #if; my solution has ended up with an ugly number of "Windows-Debug", "MacOS-Release", etc., but the differences between XS and VS make it hard to do things "right".
[1] - all source/content files added via a single template .csproj, using a Ruby watcher I'm going to eventually open-source, because using MSBuild correctly to handle this situation breaks in both VS and Xamarin. (That last bit, you may be realizing, is a common theme. .NET has such good stuff, but half of it is broken at any time.)
Keeping common code in shared projects is like night and day compared to the mess that is keeping common code in a PCL and having to deal with common APIs that aren't present (or worse, are incomplete) in your chosen PCL subset. They really clean things up a lot, even if you're treating them like they're a PCL and avoiding any platform-dependent code.
Xamarin.Forms is their solution - common UI components wrapped in a generic layer.
They have a nice way to blend Xamarin.Forms, native UI controls and library projects that is getting much better, but still a bit of a pain.
They true value in my eye is that I only have to be proficient in one language, and they have very good documentation.
I still need to have a firm understanding of the API's for both Android, iOS, and WinPhone if I want to make a non-Xamarin.Forms application, but at least I'm not mentally shifting between 3 languages.
Anyway, my point is once you understand how things are organised, the language shouldn't make much of a difference. Especially not between popular, run-of-the-mill languages like c#, java and ObjC. Your devs could probably learn iOS pretty easily.
That sums it up for me, too. I'm mostly a Ruby developer, and in C# I get tons of Ruby-like features, plus static typing and better performance. But my years with Java spoiled me for a clean and consistent stdlib. For instance in C# collections are just a mess. If I could build Rails apps in C# and deploy on Linux, I'd probably do it.
* List: implemented by ArrayList and LinkedLink
* Set: implemented by HashSet
* Map: implemented by HashMap
All are Collections.
Then it's easy to get immutable versions, synchronized versions, Sorted{Set,Map}s (implemented by Tree{Set,Map}).
They work with Comparator and Iterator in a consistent way.
There is symmetry and unity. I don't even remember the C# analogues, but my recollection is that sometimes they come with an interface, sometimes not, the names are messier, generics are less consistent, and there isn't a unified way to get immutable versions etc.
I don't think C#'s collections were that bad, and probably people here can correct my memory about some of the above, but they weren't as clean, and to me that was a motif throughout the framework. A messy collections API is no big deal really, but when it's the same story for I/O, networking, GUI, etc. . . . (I do think layout was a lot easier in WinForms than Swing though.)
On balance I'd take C#'s rapid evolution over Java's slowness, but what Java got from its conservatism was purity and low cognitive overhead, which as a working programmer was pretty nice.
That said, it'd still be really cool if I could write Rails apps in C# on Linux. With vim. :-)
IList<T>: implemented by List<T> and T[] (arrays)
ISet<T>: implemented by HashSet<T> and SortedSet<T>
IDictionary<T,U>: implemented by Dictionary<T,U>
all implement ICollection<T> and IEnumerable<T>. In the case of dictionary, it implements ICollection<KeyValuePair<T,U>>, IEnumerable<T> (.Keys) and IEnumerable<U> (.Values), etc
It's all basically the same thing. Organized and unified.
IList<T> is actually implemented by a lot of things, and the more general you go, the more things implement it. IEnumerable just allows you to get an iterator that will go through the elements. ICollection adds the ability to add and remove elements. IList further adds indexed access and order. The generic collections and operations on them are one of the best aspects of C# and the standard lib.
Except Map. See the section in the Java Collections API Design FAQ [1] on "Why doesn't Map extend Collection?".
[1] http://docs.oracle.com/javase/8/docs/technotes/guides/collec...
Then how come is Java 9+ catching up with AOT compilation, value types, making unsafe a public API, reifeid generics and replacing JNI with something more akin to P/Invoke?
Only for those that never had the pleasure to enjoy enterprise astronaut architects with their DCOM, CORBA and JEE designs.
JEE has no comparable .NET framework/library/tools.
For ref, I don't use PowerPoint, I do write (a fuck load of) code, don't organise meetings and don't speak in buzzwords. I do however have a thinkpad so that's the only stereotype...
The thing is, I've been using JEE stack and toying with Rails as well on the side. I'm amazed how Rails community changed their tone from "Java sucks" to implicitly copying the best practices in Java/JEE world.
So there ya go, my 2c.
Me, I tend to focus on the JVM/.NET/C++ ecosystems at work, and depending on the project types, I do a mix roles of architecture/development.
I love the current crazy ecosystem of languages out there, but when I need to get shit done...C# is my first choice. I've bet my career on it, and it's paid off nicely.
And as long as we're being evil, I wouldn't mind seeing Microsoft buy up Light Table (if that's even possible) and build some of its features into Visual Studio. Namely inline eval and live code modification.
Though I'd certainly be all in favor of inline eval and live coding in VS!
Last year, I inherited a .NET v4.0 project, so I've been back in Visual Studio quite a lot. And, maybe it's that my skills are rusty. That very well could be. But, the latest version of C# just feels like a sloppy mess.
It's almost as if MS started C# as a competitor to Java and now has tried to make it a competitor to everything else (Python, JavaScript, Java, etc.). I'd rather that MS have created new languages and provided transformations to port existing C# code to those languages.
Or, perhaps I've been spoiled over the last few years working with dynamically typed languages with lots of functional idioms designed in from the start.
Edit: Obviously there are some die-hard C# advocates here. So, I hope to retract my opinions. I'm clearly doing something wrong.
The big question is when using LINQ whether to use the pseudo SQL syntax (I have no idea what it's formally called) or just use the methods. I find the former hard to read/write and as far as I can tell most people have simply avoided the pseudo SQL. A quick scan through SO's LINQ tag seems to confirm that the methods are much more commonly used, whereas when it first came out it seemed to be the other way around. Then again I don;t really do much on SO any more, so may be out of touch on that.
Is that the problem you're hitting, given you are saying there are too many ways to do something?
I only wish Xamarin's products didn't cost so much. With Swift on the scene I really can't justify spending money to write my side projects in C# instead of in the environment Apple provides. Or Java for Android, which let's face it, is already similar to C# anyway.