C# 4.0: The industrial response to Lisp?
axisofeval.blogspot.com
axisofeval.blogspot.com
I've not found that to be true - C# is a lot of fun to work with.
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.
Besides... when I write SQL I write it thus:
SELECT * FROM BLAH
Then refine to:
SELECT * FROM BLAH WHERE FOO
Before finally adding:
SELECT COL1, COL2 FROM BLAH WHERE FOO
Linq matches the way I construct SQL by putting it into the order I logically think of it:
FROM BLAH WHERE FOO SELECT COL1, COL2
This seem to me to be closer to SQL syntax.
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.
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.
How practical would that be nowadays?
How long should it take? And note, most of the time is spent writing the code (~4 minutes).
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.
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.
http://www.paulgraham.com/avg.html
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.
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.
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 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.
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.
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.
clojure.org
Which is a damned shame.
It is a beautiful and fun language.
I don't understand this. What ".net baggage"? .net is a (huge) class framework that has evolved along with C#.
How is Visual Basic relevant to C#? Are you talking about VB classic? VB.net is just another language that compiles to the same IL as C#.
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 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.
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.
All the major Java IDEs have had "Go to class..." for a long time.
That's so easy to understand I definitely didn't even need to read the docs...
* (well, Emacs counts, but not to people who normally use the word IDE in my experience)
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.
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.
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.
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.
Guy Steele, in his famous talk at OOPSLA '98: http://video.google.com/videoplay?docid=-8860158196198824415 explains why "small" languages are not good.
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?).
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.
What wasn't?
- Procedural programming
- Structures and enumerations
- Overloading of functions, including operators
- 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.
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.
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.
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.