Why C# is the best language for mobile development
blog.xamarin.com
blog.xamarin.com
That is, if you're a functional programming enthusiast, you can do a lot of functional programming in C#. Sure, it's often more painful than haskell or lisp or F#, but it's workable.
If you're a dynamic programming enthusiast, C# has a perfectly workable (but ultimately unsatisfying) implementation of dynamic.
Systems programmer? Mark your code as "unsafe" and twiddle bits to your hearts content! It's not as quick or necessarily easy as C, but it's there!
Even its' OOP, which is C#'s "official" paradigm, is probably disappointing to smalltalk guys, but hey, it's better than Java, right?!
It's not glamorous or flashy, it's a workhorse language. And at being a workhorse language, I'd say it really is one of "the best".
You can get around the lack of mixins with extension methods and tight scoping but it's messy.
I was not aware that Smalltalk provided either.
On the other hand, Smalltalkers are quite keen on adding new methods to almost any existing system class, so mixins are not often as useful. Also Smalltalk development often relies on IDEs that do pretty extensive code generation behind the scenes and I think that this image based development with no real source code to speak of, and lots of reflection based development tools, is more important aspect of Smalltalk than any OO features.
this is another example of adding mixins to .net code via 3rd party library: http://remix.codeplex.com/
Clarify?
The distinction I'm drawing here is what is meant by 'natively supports' and 'supported via a 3rd party library'
Assembly provides all the mechanisms for the dynamic keyword, I wouldn't say it is a feature of x86.
The gist of it is: you can send arbitrary messages in Smalltalk (and ObjC) and the object itself deals with them somehow (with most of that being implemented by runtime anyway, but that is different issue). In C# you call methods defined by interface.
Also, you cannot modify arbitrary parts of standard library and runtime, but that is probably for the better (doing that is pretty common in ST world).
Neither C# itself nor the OP's article sell C# as being a prime language for functional, dynamic, or systems programming. Rather, it has inherited some convenient little bits of each paradigm to make the language that much nicer to write.
For example, don't want to redeclare that "List<List<LongTypeName>>" you're copying over because it has a scope of 2 lines? Just dynamically type it by calling it a "var" and be done with it. Boom: Cleaner code and zero performance hit because the compiler infers the type such that the resulting IL is identical at runtime.
Sure, given features can be misused to produce ugly or "unsatisfying" code, but that's true of any language and is ultimately the programmer's fault. Just because said features are provided, doesn't mean you need to use them. You should ultimately be using the right tool for the job, after all. C# gives you the power of having a wider choice of tools, and I love it.
member this.AddOne(i) = i + 1
and AddOne will be inferred to have the signature (int -> int).There are plenty of other annoying restrictions, too, such as locals defined by lambdas.
Places lacking type inference:
- Parameter definitions
- Method return types
- Generic type parameters (sometimes)
- Lambda expressions (due lack of syntax to indicate quoted code)
- Field declarations
The only place type inference works for declarations is in local variable declarations and lambda parameter types if the delegate type is known.Perhaps the definition of "most" is arguable, but C# has many places that need you to unnecessarily specify types, and there's no good theoretical reasons for any of it, right? (Except the whole syntax sharing for expression trees versus anonymous functions, which is debatable.)
[Digression While it is possible to use in var foo = GetIt() the practice is discouraged because it makes the type of "foo" opaque to the casual reader]
For a parameter definition, its use clearly makes no sense. What is the type for the following method?
void Demo (var x) {}
"var" in the above example would not really add much value, neither would the following example, where inference will oscillate from useless to fragile, depending on who you ask:
void Demo (var x) { var j = x.Parent; }
For method return types the reason is simple, it serves no useful purpose, in fact, it can be quite damaging as the public API contract can change during routine work. Consider a method:
var Demo (PointF f) { if (f.X < 0) return f.X; return 1; }
The above method signature cal oscillate easily between float or double on the day that someone changes the 1 with 1.2. Reading a diff or a patch file wont catch the fact that you have accidentally changed the type of the function.
If this is the kind of code that you need to write (both cases above), then by all means, use the right tool and replace "var" with "dynamic". I would argue that using "dynamic" for the sake of not declaring the type there is a poor practice, but I am not about to lecture you on poor coding choices.
Generic type paramters: your comment makes no sense.
Lamdba expressions: makes no sense, the parameters are already inferred. Not sure what value (var x) adds over the already existing (x) syntax.
Which brings us to the very case I quoted "field declarations".
The ones that you skipped where it is supported: local variable declarations, for statements, using statements, consts locals and fixed statements.
In fact, the lack of type inference for fields was said to be due to technical limitations in the C# compiler implementation, not for any language reason. [1] Sure, any product will have limitations due to schedules/resources, but that doesn't change the fact that they're unfortunate limitations that could be fixed. C# hasn't addresses these issues, but they've had 2 or 3 releases since they were introduced.
>For a parameter definition, its use clearly makes no sense. What is the type for the following method? >void Demo (var x) {}
In that case, x has no constraints (it's unused), so it's generic. Pretty simple. An unused parameter isn't that useful outside of a few cases. Usually you'll use the variable, and constraints can be inferred. Or you'll find a constraint that limits the type to a concrete type. Here's some examples:
void dub (var x) { Tuple.Create(x,x); } // x is T
void uri (var x) { new Uri(x); } // x is string
void cmp (var x, var y) { Nullable.Compare(x, y); } // x and y are Nullable<T> where T : struct
The example of "void Demo (var x) { var j = x.Parent; }" is probably one place you'd want it to fail, because using member access to infer types can get complicated, at least within C#'s type system. You'd want a static duck typing system in this case like "anonymous interfaces" or something to that effect.Arguing against return type inference is wierd: C# does that in anonymous functions - certainly you don't think we should have to annotate types there!
As for type signatures changing, if you need want to keep public contracts, then write them out! No one is saying you need to always infer everywhere, just that it's a great aid. Also, this particular example just demonstrates why C#'s type coercion is a bad idea, albeit understandable, given their desire to follow C style.
Generic type parameters. What do you mean it makes no sense? I can't write, e.g. "new List() { 1 }" - it complains List needs a type parameter. Another example: "Func<var> = () => 1". Nope, I'm required to explicitly provide the type. What if C# didn't have syntax support for Nullable<T>? You'd have to do e.g. "x = new Nullable<int>(1)" or create a helper function like Tuple and have e.g. "x = Nullable.Create(1)". Generic type parameter inference only happens on methods.
Also note that C# can't infer generic type parameter constraints - you've got to annotate them all by hand. Makes sense, I guess, because it doesn't infer any generic type parameter definitions, either.
Lambda expressions can't be type inferred. "var x = () => 1" does not work (CS0815). This is because of the same syntax for expression trees versus anonymous functions. And if that was changed, you'd still need to "promote" func somehow, due to C#'s wierd nominal typing for delegates.
Fixed statements can't be type inferred either: error CS0821: Implicitly-typed local variables cannot be fixed.
The things you mentioned, for (and foreach), using -- those are all local variable declarations. So we have it working for local variables, for some generic type parameters, lambda parameter definitions (when the lambda type is known) and lambda return types.
It's a nice start, and it makes C# far more enjoyable than some other languages like Java. But it's still quite limited, without solid reasons.
1: http://blogs.msdn.com/b/ericlippert/archive/2009/01/26/why-n...
This is perfectly fine and good - bookkeeping is one of those things that computers are good at.
I think most people don't care about dynamic typing that much -- they mostly don't want to have to write types (that, an flexible containers).
Anyway, I'm sure others will point this out, but var is NOT dynamic typing. It's type inference, which you seem to know, judging by the last sentence in that paragraph. Dynamic typing doesn't just mean that no type is declared -- it means that no type is inferred (by the compiler).
As for the var feature, you're absolutely right that I'm confusing two things there, because as another commenter pointed out, I use it mainly as a "save myself typing when it doesn't matter" feature.
In theory, a better JIT could provide as-good-as-C output, but in practice you end up screwing around and ending up with less-than-optimal machine code. But F# actually provides an advantage here: inlining. The F# compiler can inline any function, whereas the JIT is somewhat limited in what it will inline. This makes a big difference, as the CLR JIT does a much better job optimizing inside one function than it does cross-function.
I bet just about anyone with much programming experience can spend 5 minutes looking at C# and understand most of the language. It's familiar enough for anyone from a C/C++/Java/JavaScript/PHP background that it's not intimidating, even at first blush. I bet C# is more comfy for a lot of Ruby and Python folks, too.
I really, really, really like F#. The main problem with F# isn't a language or syntax problem (in fact, it's not a problem at all). F# (or other functional-first languages) isn't just different syntax-wise, it's different thinking-wise. A "good" F# program is generally written in a fundamentally different way than a "good" C# program. This is the declarative vs. imperative split. Sometimes it's really hard to convince people to change the way they think about how to go about solving a problem.
1. "Cutting edge", first thing listed is asynchronous programming. Okay, don't get me wrong, I like C#, I like the Task Parallel Library, but Grand Central Dispatch in OS X/iOS is beautifully simple and incredibly powerful. It does everything I need it to do.
2. "Powerful features" - OOP. Really? And Java/Objective-C don't support OOP/encapsulation? You can't do dependency injection in Java/Objective-C? lol.
3. "Advanced runtime" - garbage collection. I'd rather use ARC in Objective-C instead of depending on a garbage collector.
4. "Reliability" – type safety. Really? And Java/Objective-C aren't type safe? I seriously doubt that anyone considers Java or Objective-C to not be reliable languages when it comes to type safety. This is almost laughable, IMO.
5. "Easy to adopt" - easy to learn. Ok, I'll give you this one over Objective-C. But frankly, I expect a good programmer worth his salt to be able to learn another platform, and I don't consider iOS or Android to be conceptually more difficult than Windows.
6. "Fast execution. C# on iOS is powered by the LLVM optimizing compiler." Uh, I think I'd rather use Objective-C compiled with LLVM. And the bit about "performance of a low-level language"? I don't consider Objective-C to be a "low-level language".
7. "Native access" - sweet, I can use some fragile interface that breaks when Apple decides to deprecate half of their stuff. Can't wait! I love waiting for libraries to catch up.
8. "Portability" - this is a decent point, but let's be realistic - we're talking "minimally portable" here. Write-once run-anywhere is a pipe dream, IMO (at least at this point). There are always platform-specific considerations that need to be taken, and they are not always compatible with other platforms. But even still, this point should have been the main focus of the article. Points 1-7 are minor compared to this.
This just doesn't feel like a serious discussion of C#'s potential for mobile development.
Edit: just for the record, I'm not necessarily trying to refute all or some of the OP's points. I think the original article was poorly written, and the case for C# was poorly made. Hence my "let's play this game" comment.
I'm a huge fan of GCD's serial/parallel queues. I haven't found anything in C# with similar functionality that is as simple as GCD.
But it is nice. I do love LINQ-to-objects.
As to the names, I'm not sure it's safe to assume that "Map" would result in better usability than "Select", for MS's target audience.
I'd rather eat a burrito than a salad. This is not a very good technical critique of the nutritional benefits of salad vs. burritos.
> "Reliability" – type safety. Really? And Java/Objective-C aren't type safe? I seriously doubt that anyone considers Java or Objective-C to not be reliable languages when it comes to type safety. This is almost laughable, IMO.
I like Objective-C, but objectively speaking, Objective-C is horrible for type-safety. The id type is used in a lot of places (e.g. every collection class), and you can magically convert anything to anything else without a peep from the compiler through the id type. There is no easy way to say "This is an array of Foo" and have that checked.
A cursory glance at the Objective-C tag on Stack Overflow will show you a lot of programmers coming from safer languages like Java or C# who are confused by Objective-C's lack of type safety.
In practice this is not generally a huge problem once you get into the "Objective-C way of thinking," but static type checking really wasn't a huge consideration in the design of the language. It was designed with the Smalltalk philosophy of "a bunch of things sending messages to each other and responding with messages of their own," which heavily de-emphasizes the importance of concrete types in favor of interfaces.
> "Fast execution. C# on iOS is powered by the LLVM optimizing compiler." Uh, I think I'd rather use Objective-C compiled with LLVM.
This is another "I like burritos" argument.
> "Portability" - this is a decent point, but let's be realistic - we're talking "minimally portable" here. Write-once run-anywhere is a pipe dream, IMO (at least at this point).
While there will always be platform-specific debugging and often some platform-specific code required, it is indeed quite possible and even common to write portable programs. You probably use many of them. Ever used Clang? GCC? Emacs? Ruby? The Bash shell? None of these programs have a completely different codebase for different platforms. They might have some platform-specific code, but having a common, portable base is hardly a pipe dream.
I put about as much effort into my critique as the original article's author did in arguing for C#'s superiority.
> I like Objective-C, but objectively speaking, Objective-C is horrible for type-safety. The id type is used in a lot of places (e.g. every collection class), and you can magically convert anything to anything else without a peep from the compiler through the id type. There is no easy way to say "This is an array of Foo" and have that checked.
This is a problem that has bit me in the ass maybe once or twice since I started developing in Obj-C several years ago. You could magically cast things to whatever you wanted in C++, and that was never a serious problem for me back when I was developing in C++ either. As an avid JavaScript developer as well, I've had no problem with a lack of type safety. It's just not the huge demon (for me) that it's made out to be - at least in my experience.
> They might have some platform-specific code, but having a common, portable base is hardly a pipe dream.
70% code reuse across iOS and Android (see http://news.ycombinator.com/item?id=4998661) is hardly what I'd call "portable". Does the Bash shell do better than 70% code reuse across Linux / BSD / etc? I certainly hope it does.
Not really. He stated an actual fact: Proper garbage collection allows for simpler memory management than retain counting. I agree that he didn't do enough to illustrate this, but he did go further than just "I like this thing." It is indeed true that there are a number of awkward situations where you can end up with immortalized objects with retain counting that would not have been so under garbage collection (see for example the "__block id uglyHack = self" idiom in Objective-C).
> 70% code reuse across iOS and Android (see http://news.ycombinator.com/item?id=4998661) is hardly what I'd call "portable". Does the Bash shell do better than 70% code reuse across Linux / BSD / etc? I certainly hope it does.
I would rather rewrite 30% of my code than 100%. If you want to say it's imperfect and could be better, that's fine, but dismissing it entirely seems unreasonable to me.
> I would rather rewrite 30% of my code than 100%.
I agree with you on this. I'm not dismissing it - in my original post, I said the focus of the original article should have been the potential for reuse across platforms - but it was glossed over in a disappointing 3 sentences.
http://www.sellsbrothers.com/writing/refcount_rotor.doc
I'll let you come to your own conclusions about the results :)
I mean: "I put about as much effort into my critique as the original article's author did in arguing for C#'s superiority." -- Why even write your critique then? At least the original article's author had a reason, it is marketing copy.
>This is a problem that has bit me in the ass maybe once or twice since I started developing in Obj-C several years ago
The general consensus is hardly that type safety in large applications is something to not be concerned with that only bites you "once or twice" when you are a novice. So I don't see the reason for the anecdotal reference.
>70% code reuse across iOS and Android (see http://news.ycombinator.com/item?id=4998661) is hardly what I'd call "portable"
This is horribly mistaken in more than two ways.
1) Nat says: "Both of these apps are using 100% _native widgets_ for their user interface, and I think it's fair to say that both of them are fairly UI-heavy.". Which means it's a worst case scenario. For a less UI-heavy app, or one with a custom canvas based GUI etc, the percentage would be far higher.
2) 70% is far better than rewriting everything (or 0% re-use) if you use Objective-C. You could use C++ or C to write a common base, but then you're not using a single language anymore, whereas with C# you are.
3) 70% in itself is nothing to sneer at when discussing portability. Especially considering your own argument that "write once, deploy everywhere" is a pipe dream, then 70% is quite high level of reuse -- basically meaning you merely re-do the UI parts to tune it to each platform.
> Edit: just for the record, I'm not necessarily trying to refute all or some of the OP's points. I think the original article was poorly written, and the case for C# was poorly made. Hence my "let's play this game" comment.
RE: "This is horribly mistaken in more than two ways."
Not all code is created equal. That 30% that needs to be rewritten for each device could be difficult to tune for each platform. Native widgets in iOS do not work the same as native widgets in Andoid. Unless there is some magical abstraction layer (which doesn't appear to exist), you're potentially rewriting the most difficult code for each platform.
But again, please see my original post. In my original post, I said the focus of the original article should have been the potential for reuse across platforms - but it was glossed over in a disappointing 3 sentences.
Again, far better than writing ALL the code for each platform.
And in a lot of cases the GUI code is not the "most difficult", it's just the one that cannot be easily written once for all platforms (and still look native).
For example, if you make a music application, the sound engine, FFT, filters etc would be the difficult part (but it can be written just once) and the GUI layer is quite easy compared.
In short, you should not need to manually Dispose, but you might need to use weak references from children to parents.
a. because it reduces the chances of memory leaks in your code? Because in this case you negate your "every programmer worth his salt" point in #5 which we've all seen thousands of times when people explain why c++ is really the best language to be writing all software.
b. because it greatly reduces the repeated boilerplate code? Which is pretty much how I define objective c in a single word: tedium. It's been a few years but all I remember from my brief foray is comparing every tutorial to how much shorter everything would be if it were written in another language. Pretty much any language other than c++ not just c#.
If you think ARC is a great step forward then maybe you are honest enough to admit that objective c could make several giant other leaps and it might even end up looking a lot more like c#.
Do you mean "shorter" in the sense of fewer characters, or "shorter" in the sense of fewer tokens? I've found both to be true to some degree (the state of text processing in Cocoa is positively barbaric), but what people usually complain about is the former, and I can't agree that it's a problem.
I can understand why too much typing gets tedious, but I think as a criticism it's a red herring, because it's essentially the complaint that Objective-C tends to be descriptive. That's normally considered a good thing! With autocomplete, typing Objective-C isn't harder than typing code in any other language, and the descriptive names help when reading unfamiliar code. I can come across a method call in somebody else's Objective-C codebase and instantly understand what each argument is and does without having to jump around and look at definitions.
If you actually mean you have to do more, though, I think that's one of those things that varies a lot from program to program. It's not really inherent to the language.
As many pointed out when that story came out, that datapoint is highly suspicious. There are plenty of smaller languages that have surely grown much more than that (it's easier to grow more when you are small).
Also, the actual popularity is what really matters, not the increase. If C# increased 2.3% from 1000 to 1023, but say Java was at 1,000,000 and stayed there at 0% growth, then the conclusion is obvious. (Not saying those are the numbers, the point is that actual popularity trumps a few percent of growth in a year.)
> What accounts for the growth of C# in 2012? Well, the launch of Windows 8 has probably played a role — C# remains the dominant language of third-party application development on Windows devices.
Doubtful. Windows 8's launch has been a failure, even compared to Vista according to the latest figures. And is C# even the "dominant language" for Windows 8? It seems JavaScript might be just as important if not more so for Metro apps.
I think the C# advocates oversell how much it is reusable
If you STARTED with a great pile of C# code, say, running on the desktop or server, then wanted to port that to an iOS device, then you have a point.
One big problem with non-native code is that example code is almost always written in native code, and can be hard/impossible to get new features working once you try to translate across the language barrier (mobile gets REALLY finicky about when X or Y is called, especially for things like animations)
Here is a real-world example of code sharing percentages for an iOS, Android, and Mac app written in C#: http://lipsky.me/blog/2012/9/11/touchdraw-code-reuse-updated
And here is another one across iOS, Android, Mac, and Windows, also in C#: http://praeclarum.org/post/31799384896/icircuit-code-reuse-t...
Both of these apps are using 100% _native widgets_ for their user interface, and I think it's fair to say that both of them are fairly UI-heavy. And yet they average >70% code sharing.
It should also be pointed out that these apps were written from scratch. In fact, Jon Lipsky didn't even know C# before he started writing TouchDraw (the first app I linked).
Additionally, you really want "Time spent per area", which is very different from LOC in some cases.
But thanks for showing real data for named projects. Mine is from some LOC counts on customer projects (and not directly sharable), and from Mono____ advocates in the Atlanta iOS group.
I have not found this to be true for ObjC -> C# translation. In fact, it's the opposite: translating code is pretty straightforward, and CoreAnimation calls are no exception.
It's true you have to re-write the UI code on every platform, but it's still the same language on all platforms, so less of a barrier vs. a total ground-up rewrite. Frankly, I see that as a plus, else you end up with badly cloned iOS-like UIs everywhere.
[0] Should note that I'd happily be using MonoDroid if I had a say in the matter.
I too was worried about the accidentally importing iPhone UI into Android. Any tips on avoiding it?
As I said, you have to write separate UI on each platform, and you use the native toolkits (there's no fancy abstract cross-platform UI kit in Mono), so there's little chance of looking much out of place as long as you follow local conventions. It bewilders me to see native Android apps going out of their way to clone iOS widgets and stylings. Not as common lately though; you see it more in usage of PhoneGap and similar, since there's nothing stopping you from shipping an iOS-like CSS on Android.
PS: In the case of Android, I'd flip through [0], and check out Google's apps on a proper device to get the lay of the land.
Calling it "cutting-edge" is an exaggeration, too.
What is "cutting-edge" varies from person to person. Some people are easily impressed.
(I may be wrong on this, but I thought this was one of their major selling points. However, never having used the SDKs I don't know how well it works in practice)
(Disclosure: I work for Xamarin)
From my perspective, MonoTouch UIKit bindings are more convenient than original Objective C library because C# is nicer (think events, typed arrays and dictionaries, etc.)
http://iosapi.xamarin.com/?link=root%3a%2fMonoTouch-lib
You can see thousands of iOS APIs bound, including all of UIKit: http://iosapi.xamarin.com/?link=N%3aMonoTouch.UIKit
I'd personally expect we'll see a lot more JS for mobile apps: a terrible language compared to C#, but a very well understood UI layer (HTML).
Anonymous methods, unnamed classes, try catch blocks are all examples of these type of tools that when used improperly will kill the system performance, code readability, maintainability and extensibility.
We are specifically talking about C#. LINQ was specifically held as one of the improvements to the language. I am not quite sure what your point is relative to that.
There are shockingly few examples where LINQ is superior to alternatives. LINQ is the brute force technique of avoiding proper collections/algorithms.
Maybe you're refering to LINQ-to-whatever (LINQ to SQL, etc.), a LINQ generalization where you can quote your expressions, rewrite the AST and emit something else (a very constrained kind of macros, if you will).
MS is probably to blame here, but people keep conflating the two.
Take a block of code with LINQ in it and rewrite it minus LINQ but logically performing the same operations that the sugar is resolving to. To most developers it would offend the sensibilities of construction, but somehow in LINQ-land all seems fine.
What LINQ does is make your code more concise and readable. It makes it easier to find bugs and easier to understand by someone else (even if someone else is you, 6 months down the road).
It also just takes a lot less time to write.
So when you want to sort, search or transform a list, you prefer a technique which doesn't iterate over the items in the list at all? That makes no sense.
But I don't agree that LINQ is bad because someone on your team didn't know how to use a Dictionary and thought that iteration would be fast on large in-memory lists.
In many cases there are efficient LINQ constructs, e.g lazy lists, and First() not enumerating past the matching item. Hand-coding these is prone to doing it worse than Linq would. Teach your team how to use .ToDictionary() if need be.
Personally, I like LINQ a lot. I don't use it very much in my code (and usually it's for things like light filter or ordering), but it has these little things that save a lot of time.
Take another example, anonymous functions in Javascript. I've seen plenty of tremendously horrible JS code bases that were just a deep series of nested anonymous functions. Almost impossible to debug or maintain. However, when used appropriately the anonymous function is very powerful and can make certain things much easier.
List<List<Tuple<int, Dictionary<string, object>, string>>>
See also: "primitive obsession" http://c2.com/cgi/wiki?PrimitiveObsession http://sourcemaking.com/refactoring/primitive-obsession
It's in system.windows.forms isn't it? Don't really want that dependency and associated resolution being dragged in to a web app otherwise the compiler has to load the entire assembly's metadata.
Also, it requires full trust.
Oh and finally it isn't serializable.
Which is why we end up with SerializableDictionary<K, V> which is even longer and is an adaptor for Dictionary<K,V> which implements serialization.
That's why it all sucks.
And I haven't even included ConcurrentDictionary thread safety yet.
The whole thing is a fucking mess.
Because Java has been so conservative, people actively hate it's verbosity, boilerplate-ness, and lack of language features (anonymous functions, first class functions, etc.).
So Java has, for many years, helped huge teams of mediocre developers avoid certain kinds of self-inflicted wounds by being conservative in terms of language features. And the result seems to be that Java is increasingly scorned.
I know if I had to replace my C# work with Java, I'd feel incredibly frustrated at the lack of language power. In fact, I wouldn't choose to do it -- it would have to be a hell of a project or opportunity to pull me into it.
(Luckily for me, there are many better options, like Clojure or Scala on the JVM, or Haskell, Python, Ruby, etc. off the JVM).
Fine examples:
.ToList() materialization multiple times in a call graph. Ok so the thread is eating 200mb of ram?!?!?!
Generic method hell.
complete lack of understanding regarding IEnumerable, ICollection, IList etc.
O(log N) that doesn't go bang until you stick a production dataset in it.
The specification pattern - bottled rape is the only way I can quantify this. Sounds great until you have 2500 specifications and are stacking them 20 deep and your ORM decides it has had enough of clauses (EF4 bug).
My favourite: junior developer turns up and says "I wrote this awesome linq query - come and look!". Get there: all of the above.
This 'cancer' is simply a data layer; if you use proper design patterns and seperate your layers correctly, you can surgically remove this tumour and replace it with another ORM.
Your comment on "where there is no noticeable performance hits" strikes a chord because when first used there are no noticeable performance hits. But then that application grows and scales and suddenly it is death by a million paper cuts, thousands of grossly inefficient set operations devastating performance. That's aside from the fact that LINQ is often a short-circuit saving from having to think about appropriate algorithms of object-methods to deal with the likely uses.
I couldn't agree less. Any language construct can be abused, but LINQ is not particularly susceptible to abuse, unless you try very hard.
And how would using C# help me deal with the fragmentation issue ?
And nobody claimed it did.
Because we all know all the top-selling iPhone / Android apps do ship with an embedded SQL DB right!?