Sorry, but you're really attacking a straw man here.
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.
Whoa, I'm not attacking anything. I like C# a lot, but I think I'm realistic about it -- it's nobody's perfect language, except in the case of "what's a widely-adopted, multi-paradigm language that I can do typical OO stuff in, but also all that cool dynamic and FP stuff they talk about on hackernews all the time? Also, my coworkers need to be able to understand it?" That's why at the end of my reply I say I think it's one of the best "workhorse" languages.
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).
Right, sorry about that, I interpreted your post as being more snarky than it actually was in retrospect. I just love how quickly I get work done with C#, so apologies for getting defensive :)
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.
"var" is not dynamic typing. It's just a way to enable type inference - it's still as static as can be. It also has a very limited useful scope in C#, as type inference isn't supported in most areas.
I've long suspected that when programmers ask for dynamic typing, 95% of the time - or more - they are really trying to save FINGER typing, and not data typing.
This is perfectly fine and good - bookkeeping is one of those things that computers are good at.
Miguel I'm confused then - your experience with Mono certainly means you have a better understanding, but I thought I understood it pretty well, too.
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.)
"var" is a shorthand to not declare the type when it can be inferred, in most cases to avoid Foo foo = new Foo(). The point is that it avoid repetitive typing, while still preserving type safety and everything that comes with it: compiler checking that right types are used in the right places.
[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.
Honest question: Are you just playing devil's advocate? It appears that the reasoning for C#'s design is that it targets LINQ as a goal, and the new features (like var and extension methods) were implemented just for the LINQ case, not considering those features by themselves.
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.
You're right. The var keyword isn't dynamic typing. The dynamic keyword is though. dynamic C# 4.0 can do mixins, method missing, etc: http://amirrajan.net/Blog/dynamic-c-sharp
He's not attacking anything; the two of you are in (violent) agreement :). He's saying that C# provides all those little bits its "inherited", so it's an acceptably-good language for pretty much anyone, no matter your background.
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.