"I'm assuming, based on long observation, that Microsoft with high likelihood fucked up the pragmatics completely, and that programming in C#, as opposed to reading about it, is deeply depressing."
I've not found that to be true - C# is a lot of fun to work with.
C# would be awesome except that it is a very "IDE intensive" language. Don't get me wrong, Visual Studio is a very good IDE (and MonoDevelop is shaping up nicely), but I'd still prefer vim or emacs as opposed to needing a fancy IDE to be very productive.
C# is designed with IDE support in mind. For example, in Linq the "map" syntax is:
from a in b select a.x
This syntax is actually backwards compared to both SQL and list comprehension syntax is most languages, which have the selector expression is before the input list. E.g in SQL:
select b.x from b
Or list comprehensions (in eg. Python):
[a.x for a in b]
So why did MS change the syntax like this? Most developers already knows SQL syntax, and Linq queries are supposed to be able to map directly to SQL.
The reason it that it is not possible to provide code completion in the selector expression if the type of the list is not yet known. Hence in C# the list is written before the selector expression, so the editor helpfully can list all a's members when typing `select a.`
Another example is "Partial Classes" which is a curious language feature which makes it more smooth to work with UI-designer generated files, but which I don't think has any useful function outside of an IDE.
I don't think many other languages are designed with IDE support in mind in such a way. This makes it possible to provide a very smooth IDE experience.
From a theory perspective, SQL has it backwards. The projection operation in relational algebra would come last. It certainly helps with IDE interactions but it makes sense entirely on its own.
I may be confused, but according to Wikipedia http://en.wikipedia.org/wiki/Projection_%28relational_algebr... it seems that in relational algebra notation the attribute names are written before the relation, since the relation is an argument to the projection function.
The attribute names are written first, but it's like nested function calls: projection(selection(R)). The joins are 'evaluated' first, then selection (where), and then projection.
I suspect that SQL was actually designed to match the notational order (but reversing the intent) they still got it wrong: to match the notation, it should be SELECT .. WHERE .. FROM.
Interesting point, but that would apply to function notation in general, not just relational algebra.
a(b(c(x))) is "backwards" because the functions are evaluated in the opposite order than they are written. This is a flaw in math and in most programming languages! I suppose stack-based languages have it right, and the OO method chaining syntax in Linq and in e.g. JQuery has it right, since evaluation order is left-to-right.
I use this syntax all the time and greatly prefer it to the special 'from' keyword. I think it scares my co-workers a little less. There are a few cases where the from syntax is necessary, but it's not common.
I think tying language design to IDE design is absolutely brilliant. Languages are just a tool, IDEs are just a tool, we're missing brilliant opportunities if we neglect to design them synergistically.
I use Emacs/Eclipse in my job because I work with Erlang/Java, but previously held several C#/VS positions. I sometimes get the feeling that people who haven't worked with this combo don't realize how powerful it is. Visual Studio is great as an IDE for C/C++, but C#/VS just becomes an extremely productive experience, quite unlike Java/Eclipse (though the latter is getting somewhat better).
Back when I was using VC++/VS pre .NET for C/C++ I did all my editing in EMACS. Messy when I changed the line numbering out from under debugger breakpoints but it otherwise worked very well.
I feel exactly the same way. I love using vim for everything when I'm working on other languages. But there's one saving grace of VS: http://www.viemu.com -- It combines the power of modal editing, motions, and commands with the features of VS. It makes working on C# apps (or Xna games in my case) almost as nice as developing on a Unix system.
I program in Ruby, JS, Python, and C#. I love the dynamic and functional aspects of JS and Python. Once you get up and rolling with a C# project, using all the new v3.5 and v4.0 features is very pleasurable, but the facts that it's a compiled language, all but requires Visual Studio to be effective, and that getting a project up and running can be such a pain, all create a barrier to entry and to simply playing around with it. On the other hand, you do have the dynamic .NET languages like IronRuby and IronPython to play with, but you write code totally different in them than you do in C#, so it's really an either/or situation, which doesn't help.
Why is getting a project up and a running a pain? I can get a simple project up and running (a simple dialog with four buttons that moves a ball in the window) in about five minutes. That's from a no VS, to starting VS, creating the solution, writing the code, compiling, and running the app.
How long should it take? And note, most of the time is spent writing the code (~4 minutes).
Speaking for myself, it's not getting a "project" up and running that's a pain, it's getting a single line of code up and running. I don't like to have to make a project (or even a Main method) to do that; I would prefer a REPL.
When working on a big project, if I want to just test out a piece of code, I actually find myself launching the project, pausing it, and using the "Immediate" window in Visual Studio as a REPL, even though it's inconvenient for the purpose.
I also highly suggest supporting the developer of LINQPad by purchasing the auto completion (once you have evaluated the program). Its quite cheap for a licence, and makes the app twice as useful.
C# isn't a dynamic language - it is totally static. The introduction of the "dynamic" keyword in 4.0 has confused some people into thinking it is truly a dynamic language, but in actuality that keyword is just a compiler hint that causes any references to that "dynamic" variable to use run-time reflection.
FWIW, I don't agree that it needs an IDE to be productive. I often write little utility apps in C# in a plain simple editor (joe - just syntax highlighting and auto-indent) and it works just fine, no more or less than if I was writing Java without an IDE. But then, C# not as verbose as Java.
The author completely invalidates this statement with the previous, "Now, I must say that I haven't ever used C#, so I don't know how it stacks up ITRW."
It's like someone talking about Mac OS X based solely on their experience with classic Mac OS. They are entirely different products created by different people, that happen to work (or have worked) at the same huge company.
You're arguing that company track record is not a good predictor of product quality. Fine. Nonetheless, product predictions based on company track record are not "invalidated" by not having used the product, and the author made it clear what he was basing his predictions on.
_You_ may think it's fun to work with, and I guess it depends on what you think is fun (programming in Chef sounds fun, but is it pragmatic for what you're doing?).
And here's my comment to another comment on the blog post:
The question is not whether you've used C# extensively and think it is pragmatic, but whether you have used anything better (e.g. Common Lisp) and _still_ think it's as pragmatic you once thought it was. If you say that C# is more pragmatic than, say, using COBOL for an web application, then sure. But the author of this post is correct insofar as new C# features sound a lot better on paper than how they really stack up when wanting to express yourself in code.
Not to even mention that if you go outside of the OOP/procedural paradigm in C# and start coding using functional-style language constructs, C# gets pretty ugly pretty fast.
And yes, I actually wish I had more time to spend learning Lisp and using it for web development as well. See my blog (http://ifelipe.net) for what it's worth---though it's on a bit of a hiatus.
> With LINQ's expression trees, they seem to tackle the same problem as Lisp does with S-expressions.
The problem is that at the moment, it's a lot harder to work with Linq expression trees than with S-Expressions. If you're not very, very, very careful, expression trees can very quickly become an unmaintainable, terrible mess and it is very hard to debug them - it's a lot more painful than in Lisp. This might change in the future though with better tools.
Microsoft has half of the best CS minds in Europe working for their research division. Some of that genius is bound to leak into their products eventually.
I would be more interested in the bright minds that had the wisdom to find work outside Microsoft. Nothing against MS, but if half of your peers are going to the same blackhole, and you choose not to follow suit, you're either a smart fella with better options, or you're not good enough.
Assuming a 50-50 distribution; I am interested in that 25% that's both good enough, and chose to break rank. Because I have a good intuition that consensus always breeds mediocrity, never something exceptional.
I have been surprised at how little of the genuinely innovative things people are doing in Microsoft Research seem to make it into their products, but there are a lot of very interesting projects going on in their research groups nonetheless.
I can also understand the appeal of MS research. Academic CS presents a lot of distractions - the constant scrabble for funding, teaching responsibilities, campus politics etc. There are plenty of high-caliber brains in MS research. I don't think Simon Peyton-Jones, for instance, would have any trouble finding a post in any CS department.
SPJ is at Microsoft, and so are Jim Larus and Leslie Lamport. But you know what? For a behemoth that allegedly swallowed half of the computing minds in Europe, and god knows how many in the U.S., it's very sad that I can name only three top researchers, and I have absolutely no idea what they're working on.
I see more development coming out of the Factor camp, and Factor is pretty much a 25 year old guy in a basement.
Lest you think I am picking on Microsoft, I haven't been too happy with the Google language R&D labs as well. They took out billions in cash and replicated Bell Labs, circa 1986.
By the way, just think of the few recent pieces of software that made the most impact on industry; Clojure, Redis, Nginx, Memcached, jQuery,etc. All the works of random sole hackers, the last two pretty much standard resume pieces for any web developer. None of these guys existed on the map until they changed the industry with a Changelog. And because of that, I have every reason to believe that the next great engineer-aesthete is faceless today, and bumming around on friends' couches and handouts; not someone being cultivated with corporate endowments and backing.
I hope you're right honestly. The vision of the heroic hacker is much more appealing to me than that of big, bureaucratic, corporate research departments. Certainly the things small independent teams have accomplished lately is impressive.
I wonder though if there are some projects that just require more elaborate support structures. It's difficult for me to imagine that ghc or the scala compiler or postgresql could have been hacked together on the clojure model.
I'm disappointed there is no "Express" release of the latest F#. There are a couple of different hack approaches, but a .NET 4.0 F# Express would sure be nice to play with. Apparently MS has no plans for this.
The biggest problem with C# is the .Net ecosystem. Without (much) an open source community, it is and remains a tiny pond, full of crap, including a million shitty web applications and all the .Net baggage (Visual Basic anyone?)
There's a ton of open source code out there, from Mono, Gnome, a lot of projects on Codeplex, and a bunch of other sources. I don't know where the myth that there's a lack of open source .NET code came from; it's simply not true.
Thats true, but it isn't so much the baggage, as it is that you can't distribute a program written in C# unless your users have the .Net runtime installed, which is a pretty fucking big download.
It is 2010, and it still doesn't have a linker (this wouldn't have mattered so much if the programs where still distributed on a CD, but it sucks when you have to download that much).
The problem is that the people who appreciate the functional features of C# are the same ones that are already exploring other languages and paradigms outside of Java-flavored OOP.
The flip side of this is that there are a lot of code monkeys in cubicles working on C# codebases who have no interest or ability to learn the exciting features. That leaves the people who are excited about these features in the tough position of either writing the best code they can and alienating their coworkers, or finding another job.
I speak only for myself here of course, but what I find so "icky" about C# is not the language, but the development environment. I haven't used the latest VS so it might be better, but even 2007 still felt years behind the popular java IDE's, and there didn't seem to be any real competition to it either. (Someone please correct my missteps here; I'd love to know more about it than I obviously do now.)
I haven't had any issues with clunky Java IDEs since my 256mb ram IBM laptop died.
Visual studio on the other hand lacks so many of the things that made it nice to develop in Java, such as automatic implementation of interfaces, inplace renaming, the ability to move a variable from being inside a method to becoming a field at the click of a few buttons.
That said, C# is light years ahead of Java - too bad that the ide isn't.
I haven't tried VS 2010, but in previous releases there was no "Go to class..." type functionality! How is that easy to navigate? Thank god for JetBrains ReSharper plugin.
All the major Java IDEs have had "Go to class..." for a long time.
Okay, how would you design icons for abstract concepts like struct and interface? About half those icons actually make a lot of sense to me (the other half are just arbitrary symbols, as far as I can tell).
You pick those up in context pretty quickly. If you know a class has a method "DoSomething" and you see the pink block icon next to "DoSomething" and "DoSomethingElse", then you learn pretty quickly that "DoSomethingElse" must be another method.
The problem is that the overwhelming majority of C#/.NET developers ONLY have used Visual Studio. Monodevelop is not quite up to par, so really, for C#, there's only one choice for an IDE outside of notepad... I used to do more java development, but now do more C#, and I miss the the polish of Eclipse over VS (Incremental Java compiler is a huge win, Refactoring (resharper freeze my machine), Search indexes, Auto completion is still better, code navigation via back button, much better Source control integrations...)
I've used VS2005 and VS2008 extensively, and always enjoyed working with them, especially VS2008. I haven't used VS2010 much (read: at all) but am looking forward to using it.
VS2010 is IMO a far superior IDE to VS2008. Especially if you're doing WPF or Silverlight. The browser, project system, and designer is just way faster. Which is pretty surprising because the Beta for VS2010 was horribly slow.
My main ask is to get Xaml in better shape. I know that the dynamic language crowd will love Xaml, because 99% of all errors are runtime exceptions, but that's just a freaking drag on my productivity - especially since I think they can do static analysis to statically find probably 75% of the issues at compile time.
I haven't really used any of the Java IDEs out there, but I thought I'd mention that you probably mean VS2008 ;)
As for Visual Studio, its extensibility model might not be "awesome", but that is definitely changed for the better in VS2010, and for the "rest of us", jetbrains has some pretty decent products.
My main concern about C# is that with each release, it becomes bigger and seems to be more of a kitchen sink language. This phenomenon has been the downfall of other popular industrial languages, notably C++.
As the language grows, so does the number of interactions between features. All the little corner cases start to get in the way of writing clean, useful code.
As the language grows, it also becomes harder for new programmers to learn it effectively, by which I mean not just knowing the syntax, but also understanding the idioms and being familiar with the libraries to make good use of the language in practice. For real world projects that make use of the advanced features, it therefore becomes harder to find staff who are sufficiently clued up in the areas that are in common use on any given project.
The more programming I've learned, the more I am convinced that effective programming languages are simple. This doesn't mean they can't also be powerful, but the programming model is clear and the interaction between different features is either systematic or non-existent. Nearly every widely successful industrial language achieved its success initially when it was a simple language. Many industrial failures -- in the sense that they continue to be used more because of various kinds of momentum than because of their technical merit as programming tools -- became so when they stopped being simple.
I have to disagree. I've used C# professionally since its release. At first I totally agreed with you. It seemed like the language was growing like a weed and was becoming totally unmanageable. The release of C# 3 basically led me to say "what the hell, Microsoft?"
But one major counterpoint to all of this is the features added to C# 3 may seem like huge bloat at first, but when you realize they all exist to support LINQ, you end up seeing them as a pretty cohesive package. C# 3 was by far the biggest growth spurt the language has seen to date. Implicitly typed local variables, extension methods, lambdas, expression trees, etc, all exist solely to make LINQ possible. The fact that they are usable outside of LINQ is just an artifact. And honestly I think it's a good artifact, I feel all of these features have benefited the language. The more I use the new features (whether in the context of LINQ or not) the more I noticed my code becoming cleaner, more succinct and much easier to read.
C# 4 doesn't quite have the same major killer feature that 3 had to warrant its additions. But at the same time, most C# 4 features are meant for special cases (dynamic primarily makes COM interop much simpler, for example) and don't leak into day to day programming that much. Abusing these features is just a judgment call a programmer is going to have to make.
I do think MS treads a very fine line here. It would be easy for C# to fall over the edge and become "the kitchen sink", but as a very avid user, I honestly think they (so far) tread that line very carefully and quite well. Let's see how C# 5 turns out.
I have liked where the language has gone as well. I actually think that C# is a lot like Scala, with more mainstream uptake. It is not a small language, it is not simple, but it is a true multi-paradigm toolkit. You can do straight-out functional programming, lazy evaluation, OO, all out of the box. You can mix metaphors where appropriate, and the potential to end up shooting yourself in the foot is much reduced from that of C++. My biggest gripe has always been the vendor lock-in, there just don't exist the set of tools that ship with Java, particularly for profiling and configuring the VM.
What kitchen sink was thrown in C++? The STL? That's the main reason I first fell in love with C++. Templates? Exceptions? RTTI?
IMO the problem with C++ is its C legacy (things like macros). These things make it harder to read code and make it harder to write great tools for it (ever seen really good code completion or static analysis for C++ code?).
The kitchen sink comes from the conflict between the C ideology C++ inherited, and the requirement for OO language features. RTTI and exceptions are fine when you can rely on them, but C++ users don't always want to pay for those features, so you end up with some libraries that require them, others that forbid them, and some in between which reinvented their own exceptions and RTTI mechanisms. Trying to glue all these disparate things together where there's so little accepted as being in common is a pain.
Languages built around platforms, like Java and C#, on the other hand, can assume that java.lang.Object / System.Object is the root of the inheritance hierarchy, that exceptions are used throughout for error handling, that reflection is available throughout (modulo security concerns), etc. The fact that you can rely on the base library, and that you can communicate between modules using containers / common interfaces in the box makes the job of integrating modules far easier.
C++ included some of these features, but didn't make them mandatory. So you end up with a strange mix across the board.
The other issue is that C++'s features aren't well thought out in an orthogonal sense. One example: the idea of exception safety doesn't mesh well with C++'s copy constructors, to the degree that you can't write a generic stack type whose pop method returns the value popped, because you can't get exception safety right on the mutation to the stack if the copy constructor on the returned value threw an exception.
- Classes, object-oriented programming and run-time polymorphism
- Generic programming, templates, compile-time polymorphism and metaprogramming
- Text-based macros
- Hacks and, from C++0x, built-in language support for in-line functions
- Exceptions
- Low-level memory access
By my count, every one of those things interacts with almost every other one in some way. Often, there are deep connections, such as the RAII idiom, that are fundamental to using C++ effectively but not obvious to someone with a good general programming background but no expertise in C++ specifically.
The real problem, though, is that C++ isn't really very good at any of those things in isolation. There are much better approaches to all of them, and there are tools available that take those approaches. They just don't fit together to form a coherent whole, where features are either orthogonal or blended together cleanly. It used to be the case that C++ offered a more powerful overall tool than most other languages because of the diversity of its features, but today's languages have had the benefit of decades more experience and hindsight to draw on. The very diversity that used to be a compelling reason to use C++ has now become the most compelling reason not to, IMHO.
-Procedural programming
-Structures and enumerations
-Text based macros
-Low-level memory access
And for the items they actually added to C to make C++, none of them are all that unusual, save templates (not sure if there is any other language that does it compile time).
IMO, Scala has more parts of the sink in it than C++. The problem with C++ isn't the kitchen sink. It's that its built on a language that isn't meant to hold the things that C++ would like to add to it.
Maybe I'm being pedantic, but when I see "kitchen sink" I have a vision of a lot of features. But frankly C++ isn't all that feature rich. But its the interaction complexity that makes it problematic. This is not a problem of throwing the kitchen sink at it, but rather a design problem.
Several that I've worked on. There were aspects of the language that we avoided, like export, because they weren't implemented. But in general, we didn't have ground rules about features to use or not use. At least not in the past 15 years. Back in '93ish we would be more careful, because the features were still evolving, but by 2002-2003 I don't think we had a lot of issue using the language.
As the world of programming grows, I think it's natural that programmers become more specialized. I think the value provided by sophisticated, complex tools (the language and core API) is worth the additional complexity. I don't think you can avoid complexity by sticking with simple tools - you simply offload the complexity into the application code and end up in the same situation where in order for new programmers to understand the code, they have to have extensive knowledge of the application codebase.
It may even be that concentrating the complexity in the language allows programmers to more easily switch between projects and get up to speed on new projects since they're already familiar with the language complexity and thus have less application-specific complexity to learn.
I agree. It seems like if someone were to learn C# 3.0 and wanted to learn how to use LINQ with lambda, for example, they probably could figure out how to use it as far as syntax, but they wouldn't really know how it works (as far as .NET implementation) or why it was implemented, without having to back to knowing how things were done in C# 2.0.
Where C# differs from C++ in this case is that the standard actively seeks out such corner cases and defines them explicitly, whereas the C++ standard often leaves such corner cases in the "undefined behavior" realm. There is very little "undefined behavior" punting in C#.
I'm not sure how significant that difference will be in practice. It's easy to bash C++ for "undefined behaviour" or "implementation-defined behaviour", and to a certain extent it's fair criticism. However, a lot of the interactions are defined.
Unfortunately, they're defined in chapters of the C++ standard containing dozens of pages of dense language lawyerese. Even experts then get them wrong on a fairly frequent basis, and while the underlying idea behind some of the rules makes sense if you think it through deeply, the rules can still be counter-intuitive to a typical programmer who isn't a standards geek.
In other words, it doesn't much matter if the corner cases are defined explicitly, unless you can define them in such a way that they don't catch practising developers out. I have yet to see any large, complicated programming language succeed in doing this.
I've read most of the C# 1.0 and 3.0 specs. I've also read the R6RS Scheme spec and the Python 2 spec. Admittedly, I've only read a smattering of the C++0x spec. But the C# specs have always been very clear and concise compared to just about every other technical spec I've read.
Side note: R6RS is not the acme of good scheme specs, you might want to try e.g. R4-5RS sometime, especially as R6RS adaptation has been ... less than universal (heck, it proscribes a REPL (no kidding, and not by accident); it's really a different language than the Scheme before it, designed by different people).
Me, I'll probably need to use Clojure on top of the JVM someday but I'd like to get a "Turtle Clojure" developed after Clojure-in-Conjure gets somewhere ("it's turtles all the way down"). But that's because I'm not too concerned with doing anything particularly or at least immediately practical right now.
I've not found that to be true - C# is a lot of fun to work with.