Much to the derision many of the developers I know, I still say that C# is the best language I've ever worked in. But the .NET platform is one of the worst I've ever worked in. So opening up C# to more platforms sounds very, very good to my ears.
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.
I have been working in a C# codebase for the last 4-5 months. I've summed up my experience with the language like this: C# is a really good language. C#'s stdlib however is subpar.
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'm a C# developer of 10+ years. Your concerns are valid and no lost on many people. A class example being IList<T> and List<T>
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.
In a hurry is an understatement. Generics were allegedly implemented by Don Syme before the initial release of C#, but higher ups were more keen on shipping a substandard product because Generics were "only for academics".
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.
> For example, one would often like an IIndexable interface to cover both arrays and lists
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 don't think there is the distinction between Length and Count you draw - Count is O(1) for most collections, even LinkedList<T> maintains the number of elements in the list in a separate field. You could say Length does not change during the lifetime of an object while Count may do so, but I am not even sure if this distinction is always honored.
Arrays actually do implement IList<T>; they did think of that. I guess the problem is that it's not discoverable. I'd second your call for an interface on numbers (including some way to "genericise" TryParse).
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.
Arrays implementing IList<T> is a clear example of a broken abstraction though - arrays have no need for Add, Remove and whatnot that come with IList - it only needs indexing and count.
We normally think of Strings as being a special case of an array, but arguably String<T> should be a fundamental datatype, and we could do away with Array altogether. In that case, having operators for add and remove doesn't seem so crazy, especially in light of the fact that vectors often outperform doubly linked list for insertion and deletion on modern hardware[1].
Who provides a better standard library? I am a C# developer and have not that much exposure to other standard libraries, but from what I used, .NET is by far my favorite one.
There's a fair number of patterns which are now outdated, because they were created before, e.g. Generics.
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.
And they would not make arrays covariant again, the reflection API would surely use IEnumerable<T> instead of arrays, there are a couple of glitches in the inheritance hierarchy of the collections...but that doesn't really make it a bad standard library.
Nullable is not an adequate replacement for Maybe/Option, one because it is constrained only to value types, which makes it useless generically anyway, and secondly, because you can easily "bypass" it and attempt to call .Value while skipping .HasValue, causing an exception to be thrown. C# lacks the necessary features to have a useful Maybe type - namely exhaustive pattern matching and the Unit type.
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.
You don't need it for reference types, because those can just return a null.
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!
>You don't need it for reference types, because those can just return a null.
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.
Nullable is the perfect solution for TryParse. The InvalidOperationException on null is the equivalent of the NullPointerException you would expect for a reference class TryParse method.
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).
What's frustrating is how few things got the needed TLC after generics and nullables were added.
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.
That doesn't work for a standard library - it may make you happy, but the next developer may have very different needs. Int32.TryParse() does not distinguish between null and empty strings and it takes only a minute or two to create an extension method and the problem is solved once and forever.
public static class StringExtensions
{
public static Int32? ParseAsNullableInt32(this String self, Int32? fallback = null)
{
Int32 result;
return Int32.TryParse(self, out result) ? result : fallback;
}
}
Yes, that's the obviously implementation, but so many older framework libs that have not been replaced still use serializers that, when given a Nullable type, fail to use that obvious implementation and blow up on empty strings.
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.
Likewise Async. The basic file IO and ADO.NET APIs can be wrapped up in awaitable structures but you pretty much have to do it yourself. For most purposes if you really want to make good use of C#'s cleverest language features you have to write wrapper classes around .NET to make it work.
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.
WPF is so much better than (almost) everything else out there (that I am aware of). Yes, it is very different and switching from WinForms is hard to say the least, but it gets so many things right, is extremely powerful and really fun to use once you wrapped your head around it.
Java's library is on the whole better than C#'s. But if you want an example of a stdlib that really sets the bar then I would point to Go. In particular the io packages. They are so composable and simple and easy to use that it makes me want to cry at their beauty sometimes. Go has one of the best written stdlib's of any language I've ever used.
Xamarin's value proposition is developing for multiple platforms at once (or at least, as a current Xamarin user, sharing as much as possible between platforms). Swift still offers nothing for that scenario so I don't really understand the comparison.
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.
Last time I tried Xamarin (and I'll admit it's been a while) cross-platform was surprisingly difficult. A project had to be either iOS or Android - and that included projects that had no UI code in them. So the concept was there, but the execution wasn't yet.
Portable Class Libraries help here. They aren't perfect, and honestly they're justly badly reinventing Java's loosely coupled jars, but they give you the ability to link stuff together in a little more general of a way.
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.)
Assuming you don't need to pass around binary libraries, take a look at shared projects-- added in Visual Studio 2013 and Xamarin Studio 5, IIRC. Unlike PCL projects, they compile in the context of the projects that reference them, so you have full access to the libraries that are common between each platform, and (if your coding style allows it) full access to platform-dependent APIs as long as they're protected by the appropriate #if __IOS__/#if __WIN32__/etc.
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.
Ooh. I didn't know about this. I'm using VS2012, because I don't want to shell out again for VS2013 but want ReSharper - I'll have to look at this...thank you!
There is still a degree of that, depending on how you structure the application, and how much of it is reliant on your UI layer vs backend business logic.
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.
I suppose the value is that you don't have to rewrite your application logic multiple times. That takes time even if you're fluent in all languages. It is also a duplicatio which increases the risk of later bugs due to not doing all changes in all copies.
Exactly - and as a after work only developer, the less I have to do over, the less I have to consult the docs, the more comfortable I am with a single tool, the more productive I become.
At work we use Xamarin for iOS-only projects, as we're primarily a C# consultancy. It's expensive, but it would be more expensive and difficult to find or train native iOS developers. Or at least, that's the impression management is under. The fact that we could port an app to Android somewhat easily when a client requests it is just icing on the cake, since almost all of our mobile projects are iOS only.
Interestingly, most of my experience is in c#, but I've now got a side project that requires apps. I wrote them in Android and iOS. I looked at Xamarin as well, but I couldn't see the point of learning essentially a new framework. I figure whatever pattern you use (probably MVC) it will be the same on both. And the layout paradigms are different between them, so how is Xamarin going to fix that? My solution was just to use webviews instead of the native layouts (decided after bashing my head against both layout engines).
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.
I agree. However, there is a lot of fear among developers in my area with regards to learning new languages. Many developers I know would rather learn 20 new frameworks than a single new language. Managers feel even more strongly along those lines. I don't share their views, but I think I am in a minority.
> C# is the best language I've ever worked in. But the .NET platform is one of the worst
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.
I haven't used either in a few years, but Java's are trivial to remember:
* 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. :-)
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.
Thank you for your correction! I am still suspicious that there is some forgotten weirdness lurking in there, but I'm glad someone didn't let me propagate my mistaken recollections unanswered. :-)
They basically took rails, removed active record, dropped in EF, gave it a better templating language, gave it static typing via C#, and threw it into the mix w/ webforms and called it a day. They've been improving it constantly since as well.
> But the .NET platform is one of the worst I've ever worked in.
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?
"enterprise architect" here. Yes you just stamped on a lot of our toes and rightly so. There is a lot of batshit out there which is what you've most likely experienced. There are a few of us working to destroy this batshit without sacrificing the ultimate goal of building something that isn't a bag of rats though, so please don't tar and feather us all.
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.
Unless of course, you want your side projects to work on non-Apple platforms. Aside from mobile stuff (and who really cares about that ;), the remainder of the Xamarin/Mono toolset is feature complete and almost entirely open source.
I've developed in C# professionally since 2002, but also have created endless critical systems with Java, C/C++, and VB6 (yes I said Visual Basic 6...real world programming can be an unholy bitch sometimes.)
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.
I bet Microsoft would like to buy Xamarin too, but worry that might strain Xamarin's relationship with Apple and/or Google. This could be a "if it aint broke, don't fix it" scenario.
Actually that sounds so reasonable. I have been asking myself why Microsoft hasn't bought Xamarin. But Xamarin is actually an amazing Trojan Horse for Microsoft.
If by some miracle Visual Studio ever ran on non-Windows platforms, Microsoft would then be free to kill off Xamarin Studio.
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.
Interesting. I knew VS had been working toward features like that; I wasn't aware they'd come as far as they have. Though from my poking around there appear to be some limitations: no redefining lambdas in a live session, for example. And I'm pretty sure that Instaparse is still out of reach, though that's not really what was being referred to. But thank you for reminding me, it's been a while since I've had an occasion to touch VS.
I used to be a hardcore C# developer. From the initial beta of .NET through v3.5, I used it at least 25% of my time. But, since then I've not used it.
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.
The big features that were added after c#3 are dynamic references and async. They both seem to be quite well done as far as I can tell. Could you comment more specifically on problems you saw?
Could you elaborate what's so messy in your eyes? Most features that were added are more or less only visible if you actively use them and shouldn't distract from anything.
Again, I could be using C# stupidly, or the existing code that I have could be all hacked up. But, it seems like C# is trying to be everything to everyone. There are too many features of the language that allow things to be done many different ways. This leads to a lot of inconsistencies when the code base is relatively large and there are lots of developers working on it. Some things just seem 'bolted on', like unit tests, functional idioms, NuGet, etc.
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.
3.5 => 4 hasn't really changed the way you should code much, so it's a bit confusing what about it you suddenly don't like? All the functional stuff was added in 3.5, 4 was really optional/named params, which are a godsend, dynamic, which you should use once in a blue moon, and a bunch of stuff to make COM interop easier.
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 was more curious why C# is one of the best. Last time I looked at it (quite a while ago now), it was very like Java, and not many people rant about Java any more.
C# has improved a lot faster than Java the last 5-6 years. I would say it is has been a much better language until recently when Java 8 was released. Now they are more equal with Java probably having some advantages since it was the last to update.
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.