|
So, there's not a whole lot of information in the article, and some of the points may be debatable, but the message of 'as you use var consider the impact on readability' is fairly uncontroversial I would have thought.
The diversity of the software ecosystem is evidence for the fact that beyond the trivial very few things can be analysed through this lens of 'proof' you speak of.
|
|
|
|
|
Ok, could be my overreaction... in my opinion, this is just right.
Does it disproof any of my points?
Please pay attention, I do not argue with any of the technical aspects of the article, even though I could.
IMHO, this is the author of the article who is supposed to motivate every single claim in this article, give us use cases or whatever he might need to illustrate his opinion, and only then we could argue with them. Before this point, this is even worse waste of time.
And I still can not tolerate when the author replies to criticism (in my opinion, often much more mature then the author's statements) with plain, irrelevant and rude accusations; there is a big difference between criticism (even aggressive) and accusations. And I simply don't think it would be appropriate to reply to such accusations. The whole discussion should not be accepted.
As this this thing:
"The diversity of the software ecosystem is evidence for the fact that beyond the trivial very few things can be analysed through this lens of 'proof' you speak of."
You're right in general. In this case, however, I think many points of the discussion are still in the "trivial" domain.
This is not the most important point. The important point is the certain standard for argumentation.
If the author adds enough depth to the article to support his claims and reacts to criticism adequately, then we have something to discuss.
Sergey A Kryukov
|
|
|
|
|
just an opinion not based on any fact, or authoritative source
|
|
|
|
|
Agree with you vote.
However, it must be said, "authoritative source" is never a legitimate argument. It should only be used to supplement facts and proofs.
Sergey A Kryukov
|
|
|
|
|
Suggested best-practice in the article isn't universally agreed, and not there is not much support for it in the article. Totally hostile response to valid questions in the discussion without actually understanding other posters point of view.
|
|
|
|
|
The posters were actually, i felt, not getting spirit of the article, getting stuck 2 just 2 lines of the whole article.
It sounded, as if they are on a mission to make such comments. I wonder why....
See this "/http://msdn.microsoft.com/en-us/library/bb384061.aspx", to talk about var, there is a contextual reference to Object or variant.
"...var keyword does not mean “variant” and does not indicate that the variable is loosely typed, or late-bound..."
Another excerpt "/http://msdn.microsoft.com/en-us/library/bb384061.aspx"
"However, the use of var does have at least the potential to make your code more difficult to understand for other developers. For that reason, the C# documentation generally uses var only when it is required."
Further,look the an interesting excerpt mentioned in the fourth, from last, comment in this article:
http://blogs.msdn.com/abhinaba/archive/2005/09/15/467695.aspx[^]
"
to quote the MSDN documentation:
"Overuse of var can make source code less readable for others. It is recommended to use var only when it is necessary, that is, when the variable will be used to store an anonymous type or a collection of anonymous types."
http://msdn.microsoft.com/en-us/library/bb383973.aspx"
In http://blogs.msdn.com, many blogger have recommended the same, so why is there a denial of the same here?
modified on Monday, November 9, 2009 6:10 AM
|
|
|
|
|
|
Why to create post to redirect to another?
|
|
|
|
|
I see that the boxing-related comment early in this article has provoked commentary. I think I understand the reasoning behind the author's comment.
Prior to "var" it was possible to do something like this:
Object whatever = ObtainInstanceOfType1();
Object whateverElse = ObtainInstanceOfSomeOtherType();
Object itWorksForEverythingHaHaHa = 3;
At a very superficial level, many of the benefits of "var" were obtainable by using "Object." Of course, this results in a performance hit as value types are "boxed" into the object references, and I doubt that any real-world programmer was doing this. So, to me also, this seems like a pretty queer way to explain "var."
However, I do not think this author is alone in making this peculiar argument. I'm fairly certain I've seen it on MSDN. He may simply be parroting something Microsoft said.
I have been saying for the last 2 or 3 years that Microsoft provides decent development tools but very bad advice about how to use them. Or, put more flamboyantly, "the beginner reads MSDN. The intermediate programmer parrots it. The advanced programmer not only avoids MSDN, he burns up the documentation that came with Visual Studio."
The "poster pack" makes great kindling, and I do not need or want a drawing of a Microsoft Quasi-Superhero anyway.
|
|
|
|
|
> At a very superficial level, many of the benefits of "var" were obtainable by using "Object."
Indeed, at a *very* superficial level, because you can't do anything with the variable without casting it back to the original type. So you're writing the type name not just once, in the variable declaration, but every time you use it.
The code is just uglier and harder to understand, that's why nobody used this style of variable declarations, not because of any boxing/unboxing overhead.
|
|
|
|
|
>Indeed, at a *very* superficial level, because you can't do anything with the variable without casting it back to the original type.
>So you're writing the type name not just once, in the variable declaration, but every time you use it.
Not always... in fact, many of the early-vintage .NET Framework classes seem to be built around using Object without casting, e.g.
Object o = "Hello, World of Warcraft";
Console.WriteLine(o);
o=44;
Console.WriteLine(o);
ArrayList al=new ArrayList();
al.Add(o);
The last two statements are particularly revealing. Microsoft was not so anti-boxing back then as they are now. Presumably there were also many early .NET libraries build similarly around "Object," or (in a related but somewhat better strategy) some more specific base class.
After a certain point, Microsoft started to care more about performance, and they introduced features designed to move polymorphic operations forward-in-time, from execution-time to compilation-time. Then, they gave us generics (which are still pretty brain-dead compared to C++ template classes), "var," etc.
So, the mention of "unboxing" in the article is not that out-of-place. It probably warrants more explanation, or perhaps treatment further down in the body of the article. But this is not so much ignorance or stupidity on the part of the author as it is ignorance / stupidity by Microsoft.
|
|
|
|
|
Member 3680785 wrote: Object o = "Hello, World of Warcraft";
Console.WriteLine(o);
o=44;
Console.WriteLine(o);
ArrayList al=new ArrayList();
al.Add(o);
This is precisely not what the var keyword does... try if for yourself, replace Object with var and you'll see that the code no longer compiles.
Console.WriteLine has an overload for int, so it doesn't perform any boxing/unboxing if you call Console.WriteLine(44). In your example the boxing happens in the 'o=44;' line, which I argue very few developers would use. After all, declaring another variable would require just 4 more characters.
Member 3680785 wrote: The last two statements are particularly revealing. Microsoft was not so anti-boxing back then as they are now. Presumably there were also many early .NET libraries build similarly around "Object," or (in a related but somewhat better strategy) some more specific base class.
Microsoft did care about performance from the beginning, you could always use straight arrays instead of ArrayList. In fact that's how most of the early APIs work.
Member 3680785 wrote: After a certain point, Microsoft started to care more about performance, and they introduced features designed to move polymorphic operations forward-in-time, from execution-time to compilation-time. Then, they gave us generics (which are still pretty brain-dead compared to C++ template classes), "var," etc.
I don't know what you mean with "moving polymorphic operations forward-in-time", but generics don't do this (they just remove a downcast from Object to your type), and 'var' certainly doesn't do it (since the compiled IL looks exactly the same with or without var - remember that your example does *not* work with var).
|
|
|
|
|
dberindei wrote: This is precisely not what the var keyword does... try if for yourself, replace Object with var and you'll see that the code no longer compiles.
I never claimed that "Object" and "var" were equivalent at a text replacement level. I made the point that either one could be used, in some sense at least, as a typing shortcut to avoid tediously re-entering the same type name within a single declaration. This does not necessarily require a bunch of typecasts, as you claimed. I can make my own methods take Objects, and then no casting is required. You probably think this is a crappy approach, and I agree. But some of the .NET Framework methods take this very approach- hence my mention of ArrayList.
dberindei wrote:
Microsoft did care about performance from the beginning, you could always use straight arrays instead of ArrayList. In fact that's how most of the early APIs work.
Sure, I could have used arrays, if I was willing to allocate the storage myself, worry about sizing it, etc. Most programmers justifiably will not want to do this, and use of ArrayList was thus very pervasive in the early days on .NET. If you don't believe that, I'm sorry, but you've got your head in the sand.
Beyond that, I think your line of commentary exhibits a bit of historical revisionism. Around the time they started hyping Vista and WPF, Microsoft started pushing .NET as a high-performance technology. WPF is supposed to be fast, and it's intimately coupled with .NET 3.0. That means that, unlike prior versions, .NET 3.0 couldn't aim at the (low) performance of Java. Now, Microsoft was claiming that it was fast in an overall sense.
There was a transformation in thinking that happened, and you can deny it, but things like ArrayList still exist and they betray the fact that .NET was originally intended much more as a "toy" or "boutique" technology than what it's (unfortunately) become today, i.e. the answer to Everything You'll Ever Actually Need To Write (TM) Brought to You By Microsoft.
Of course, the value of making things slower for Microsoft is that existing hardware will become inadequate, and will need to be replaced. This hardware will be purchased with a brand new copy of Windows already paid for.
Also, Microsoft is only too happy that more and more code will be written in C#, which cannot even execute without their continued legal permission. Code written in .NET basically has its real ownership shared with Microsoft. If Microsoft decides it shouldn't compile, it won't. They certainly don't mind that, and if lying about .NET performance is the price that must be paid to this end, they apparently have no scruples about that.
dberindei wrote: I don't know what you mean with "moving polymorphic operations forward-in-time", but generics don't do this
"Generics" in the overall sense (e.g. C++ and Java) definitely do move things forward in time. If you make a C++ template, for example, and then use it for (say) type "int," then code gets generated at compile-time with "int" put in place of your type parameter name. So, by the time the code actually runs, any operations related to dealing with multiple types are gone. The executing code deals with data exactly as if you'd coded an entire library around "int," even though it was written around some hypothetical type probably named something like T or U. Compared to a polymorphic approach to the same problem (which almost always exists, and ends up checking types and dereferencing a Vtable at runtime) operations are indeed moved forward in time, i.e. to compilation.
I have researched C# "generics" a bit, and they are not implemented this way. C# "generics" are inherent to IL and thus survive the build process. So you are correct in that sense (although I think I could come up with some examples of type checking that do "get moved forward in time" by C# generics).
However, I should also point out that I find this design to be asinine. IL has basically turned into Yet Another High-Level Language. It is no longer an assembly-like language like UCSD p-Code or Java bytecodes, both of which were in fact actually implemented directly in hardware at one point. IL has become just another bloated layer standing between the .NET programmer and the hardware.
Beyond that, in C++, I am allowed to take hypothetical types T and U and write code that attempts to do basically anything with them, e.g.
template <class T >
void()
{
T t1, t2;
//etc... Eventually, we try this:
t1+=t2;
}
I have blatantly assumed that "T" supports addition, with no basis in fact. But in C++, this compiles without error, unless and until someone uses the template for a type that really doesn't support addition.
To my mind, this is a key part of the power of C++ templates, and it's completely missing in .NET. C# generics, for example, simply fail at compile time if you make assumptions like I did in my C++ example.
modified on Saturday, November 14, 2009 10:16 AM
|
|
|
|
|
Member 3680785 wrote: I never claimed that "Object" and "var" were equivalent at a text replacement level.
My claim is that they are fundamentally different. var is only syntactic sugar, while Object changes the meaning of the code.
Member 3680785 wrote: I can make my own methods take Objects, and then no casting is required.
If all you want to do with your object is add it to a collection or pass it to another function, you don't need a variable at all, so there's no point in talking about var/Object in that case.
However, if you're the one writing the methods, you need the cast inside the method. Plus you lose the type safety of C#, because your method can be called with objects of any type instead of only being called with your super-long-named type. There are situations where you want generic methods that can handle parameters of any type, but var was not designed for those situations. It's just a way to reduce typing and to make the code easier to read.
Think of it as auto in the upcoming C++0x. You wouldn't ever think of these lines as remotely equivalent in C++, would you?
<br />
auto i = 1;<br />
<br />
void* i = &1;<br />
Member 3680785 wrote: That means that, unlike prior versions, .NET 3.0 couldn't aim at the (low) performance of Java.
.NET 3.0 did not change anything in the .NET CLR, all the changes were in the class libraries. See Wikipedia[^].
Member 3680785 wrote: "Generics" in the overall sense (e.g. C++ and Java) definitely do move things forward in time. If you make a C++ template, for example, and then use it for (say) type "int," then code gets generated at compile-time with "int" put in place of your type parameter name.
In C++ the int type does not have any polymorphic operations, so there is nothing to move to compile time. You can certainly think of generics as an alternative to polymorphism, but once you've made a method virtual it remains virtual whether you put it in a template or not.
And I don't know why you brought in Java, because their generics are much weaker than .NET's: they are basically just syntactic sugar and they have almost 0 influence on the generated code.
Member 3680785 wrote: However, I should also point out that I find this design to be asinine. IL has basically turned into Yet Another High-Level Language. It is no longer an assembly-like language like UCSD p-Code or Java bytecodes, both of which were in fact actually implemented directly in hardware at one point. IL has become just another bloated layer standing between the .NET programmer and the hardware.
p-code and Java bytecode were both designed to be interpreted, while IL was designed to be compiled. The first JDK to have a JIT was 1.1[^]. And IL was generic from the beginning, see this interview with Anders Hejlsberg on Artima[^]
Member 3680785 wrote: I have blatantly assumed that "T" supports addition, with no basis in fact. But in C++, this compiles without error, unless and until someone uses the template for a type that really doesn't support addition.
You didn't get any error, but that didn't mean your code was actually compiled. In C++ the template definition is compiled (again and again) every time it is instantiated with a new type (in one compilation unit; different compilation units will again compile the same template for the same template parameters).
The fact that you can write a library and have it compile with 0 errors until someone actually tries to use it doesn't seem a strong point of C++ to me.
|
|
|
|
|
I'm going to go on the whole "C# doesnt have templates". Bullshildt. Here:
class bob
{
private var _some_internal_thing;
public bob<type T>()
{
_some_internal_thing = new T();
_some_internal_thing += 4;
}
public var steve<type Q>(T potato)
{
return (Q)potato;
}
}
This is logically valid code. It really is. It wont compile though, I Dont think, but its still technically valid code.
I've used these kinds of schemes to make XML (de) serializers
*turns off the internet vigilante syndrome*
Now, gimme a potato.
|
|
|
|
|
Sorry, your code is not logically valid. Even in C++ all class members have to have a type. What should the compiler deduce to be the type of _some_internal_thing in your example?
What if the constructor never assigns the _some_internal_thing member? What type should it have then?
If we move _some_internal_thing to be a local variable in the constructor, the code will make sense for some type parameters, but not for all. Sure, you can say that you will only ever use the constructor with numbers, but your code is not logically valid until you add that restriction (which you can't do yet in C# or in C++).
|
|
|
|
|
dberindei wrote: Sorry, your code is not logically valid. Even in C++ all class members have to have a type. What should the compiler deduce to be the type of _some_internal_thing in your example?
It has a type. Its of type "var" -- its an indeterminable.
dberindei wrote: What if the constructor never assigns the _some_internal_thing member? What type should it have then?
It has to. There is only one constructor (therefore no default constructor) and therefore you always define _some_internal_thing
dberindei wrote: but your code is not logically valid until you add that restriction (which you can't do yet in C# or in C++).
Sure I can.
<br />
if( T is not ValueType)
{ throw new ArgumentException("Bad you, you didnt give me a type thats a valueType."); }<br />
|
|
|
|
|
Indrora wrote: It has a type. Its of type "var" -- its an indeterminable.
If you were talking about a dynamically typed language like Python or Ruby then that's perfectly valid code. But there is no such thing as an "indeterminate type" in any statically typed language I know of.
It's a simple rule really, in a statically typed language the layout of an object must be known at compile time. If you have a member variable you must know its type in order to determine the layout of the containing object.
Indrora wrote: It has to. There is only one constructor (therefore no default constructor) and therefore you always define _some_internal_thing
Yes, your constructor defines _some_internal_thing . But what if your class looked like this?
class bob
{
private var _some_internal_thing;
public bob<type T>()
{
}
}
And after you answered that, think about multiple assignments to _some_internal_thing in the constructor, like this:
class bob
{
private var _some_internal_thing;
public bob<type T>()
{
_some_internal_thing = new T();
_some_internal_thing = 0;
_some_internal_thing = "";
}
}
What would be the type of _some_internal_thing then?
Indrora wrote: Sure I can.
if( T is not ValueType) // Is-A query :V
{ throw new ArgumentException("Bad you, you didnt give me a type thats a valueType."); }
Sorry, I fail to see the connection between T being a ValueType and having an operator +(int) .
And even if you replace T is not ValueType with a hypothetical T has operator +(int) expression, your condition is only evaluated at runtime. It cannot possibly help the compiler must decide what type _some_internal_thing should have and which method to call to do the addition.
|
|
|
|
|
This comparison is pointless. Things are fundamentally different:
Object-based declaration is up-casting. It can always be done, but later use of the variable may create problems which can be solved only by dynamic or static down-casting: static could be unsafe, dynamic could present a performance hit; both ways can be considered as OOP abuse.
In contrast, with type inference
var whatever = ObtainInstanceOfType1();
is normal static typing.
Assuming declaration
Type1 ObtainInstanceOfType1();
this is the same as
Type1 whatever = ObtainInstanceOfType1();
Sergey A Kryukov
|
|
|
|
|
I think the comparison is made necessary by the choice of keyword.
The keyword "var" hints at "variant." I think what Microsoft meant to hint at was "variable."
In either case, to me and probably to you as well, it doesn't matter what they called it. A minute spent researching the issue reveals the precise purpose of the keyword. It doesn't matter if the name is meaningless, or even obscene (it happens - e.g. "mime sniffing"). I have access to the documentation, and I can understand it, so I can thus use the keyword effectively.
But to others, who are coming from some variant-heavy language where "var" (or, at least "variant") means something vastly different, there is a dangerous tendency to make an incorrect assumption which basically equates "var" to "Object."
Of course, I don't think this particular article has helped to clear up the confusion. It really is editorially muddled, and I too get plenty pissed off when people parrot the words of unseen "authorities" instead of giving a real explanation.
I don't even see the point of this article or many like it... he is trying to tell me when to utilize some tiny, obscure piece of syntactic sugar in the language? I don't need that. There are plenty of things I do need that I'd be glad see even a crappy article on: a port of OS-9 to the Commodore Pet; a thread-safe version of GDI32.DLL; a Mac-hosted emulator for the BusiComm 9000 RPN calculator; support for half-precision floats in Excel VBA; Hungarian language support in EasyWriter 11.1; whatever. But what I do not need is any more advice.
That said, I do see why he would mention boxing (see my post above), although I think he completely botched the explanation. My post does a better job.
|
|
|
|
|
I agree with you.
(What I did not think about in first place and what looks funny to me is that I did not even have a remote idea or association between "var" and "variant". In my mind it was only related to "variable", mostly from long Pascal/Delphi experience.)
I also don't need or appreciate this kind of advice in principle.
However, my point was to protect others from getting similar "help".
Many times I had collisions with some of my colleagues. When I ask why they did not use some really good and simple technique, sometimes they answer:
"Because I have read an advice in an article that this is dangerous practice". But why this advice was taken? You know what I mean...
As to this very article, we don't even have a subject for discussion.
Thank you.
Sergey A Kryukov
|
|
|
|
|
The article is simply wrong. Boxing\unboxing argumentation is wrong. Using "var customer = new Customer()" is a recommended practice from MS developers. See also
http://stackoverflow.com/questions/209199/whats-the-point-of-the-var-keyword/209261#209261
|
|
|
|
|
Utwig wrote: The article is simply wrong.
Ohh, really? Can you please be specific on your concerns?
Utwig wrote: Boxing\un-boxing argumentation is wrong.
I have been addressing this issue here in this comment "http://www.codeproject.com/Messages/3260191/Boxing-and-implicit-typing.aspx". I request you to go through my responses on this thread and then put specific comments, in case your understanding does not get mature.
Utwig wrote: Using "var customer = new Customer()" is a recommended practice from MS developers. See also
http://stackoverflow.com/questions/209199/whats-the-point-of-the-var-keyword/209261#209261
I can just lough, it seems you are in a mission to make such comments. You did not even properly read my article nor understood the stackoverflow article.
Here is was stackoverflow says:
"...instead of
SomeGeneric<VeryLongTypename<NestedTypename>> thing = new SomeGeneric<VeryLongTypename<NestedTypename>>();<br /> , consider
var thing = new SomeGeneric<VeryLongTypename<NestedTypename>>();<br /> ..."
Which is pretty much the same, that I wrote :
1. Do use ‘var’ to:... c.Refer complex generic types.
What are you talking about then?
|
|
|
|
|
Utwig,
I would agree with you if you argued that "var customer = new Customer()" is good practice.
But you also need to argument correctly, considering the essence of the topic instead of just referring to some "authorities".
Sergey A Kryukov
|
|
|
|
|
The implicitly typed 'var' is just a compiler trick that makes life easier for us developers. C# 3.0 was released with no new CLR so nothing changed under the hood.
There has been some discussion around
int i = 2; vs. var i = 2;
they are the same thing.
here is some code that i slaved over for your consideration
private static void CreateImplicitInteger()
{
var i = 2;
}
private static void CreateExplicitInteger()
{
int i = 2;
}
the 2 methods produce the same IL:
.method private hidebysig static void CreateImplicitInteger() cil managed
{
.maxstack 1
.locals init ([0] int32 i)
IL_0000: nop
IL_0001: ldc.i4.2
IL_0002: stloc.0
IL_0003: ret
}
and
.method private hidebysig static void CreateExplicitInteger() cil managed
{
.maxstack 1
.locals init ([0] int32 i)
IL_0000: nop
IL_0001: ldc.i4.2
IL_0002: stloc.0
IL_0003: ret
}
Also, i would disagree with the author and encourage people to use var like so:
var customer = new Customer();
This can really save you time and effort when refactoring.
Let's say that i decide to create a CustomerBase class ot inherit form and then decide to new up my Customer as a CustomerBase.
If I use Implicit typing then I change my code in 1 place.
var customer = new Customer();
If I use Explicit typing then I change my code in 2 places.
Customer customer = new Customer();
|
|
|
|
|