Are people abusing "var"?

M

Michael B. Trausch

I'm not sure I understand what ABI-breaking change is.

An ABI-breaking change is a change that requires a recompile of
application code against a library. Since the "var" is resolved to a
real type during the compilation, it'd alter the library in a way as to
no longer be compatible with its internal self, if "var" were being
used to interact with whatever changed, and whatever changed was public.

ABI, by the way:

http://en.wikipedia.org/wiki/Application_binary_interface

--- Mike
 
M

Michael B. Trausch

</snip>

Umm, I would LOVE to see how that works when you send that code to a
printer....too bad we can't mouse over the variables on a sheet of
8½" x 11" paper! :) So, to say "you never have to figure out the
type later" is a little off....specially when you want to print code
to the printer for some reason (I've done it, although I 999 times
out of 1000 I don't print code).

LOL, usually when I print code, it's code for something that someone
wrote in a language that doesn't do static typing, like PHP, so that I
can use a pencil and figure it out when it's a royal mess. Best way to
get to know the code, I think!

I do much rather not having to do that, though.

--- Mike
 
A

Anthony Jones

Christophe Lephay said:
MC said:
Michael B. Trausch said:
On Tue, 25 Nov 2008 15:19:24 -0000

Even though C# makes a reasonable stab at choosing the most
appropriate datatype
(http://msdn.microsoft.com/en-us/library/bb384061.aspx), I prefer to
tell it what I mean explicitly rather than allow it to decide what it
thinks I mean implicitly...

Absolutely. This is one of the reasons that I choose to use statically
typed languages at all: not using some mechanism like "var" eliminates
many classes of code by specifying _precisely_ what you want. While
"var" is easily figured out by the computer, it's far easier for a
human to see "int" or "string" or even "object", if it must be.

[ "many classes of code" => "many classes of coding errors" ? ]

Right! By declaring types, you make sure the compiler knows what YOU are
thinking, so if you make a mistake later on, you'll be warned!

This was one of the key insights in the original design of Pascal (which,
despite superficial differences, is an important intellectual ancestor of
C#): Let the compiler help you keep >track of what YOU think the data
types and structures should be.

But this is not an issue with auto.

Var doesn't mean variant, and the object is still strongly typed. If the
compiler can deduce what you mean without any ambiguity, why should you
still need to say it ?

Another thing to consider is that var can only be used locally. So, if the
reader has a problem to understand what is the real type of the object
(let's suppose the intellisens won't tell him), i guess there is something
very wrong either with the function, either with the reader.

And because the object will be very local, to know preciseley what is the
type of the object will be useless most of the time, as long as the
compiler can do its type checking.

I don't agree. To know 'preciseley' what something is when reading a chunk
of code is exactly what a programmer wants.

Consider:-

void DoStuff()
{
var col = GetThings();
if (col.Length == 0)
{
//do stuff with col.
}
}

At glance is col.Length something you can do to col? Now look at these
versions:-


void DoStuff()
{
Thing[] col = GetThings();
if (col.Length == 0)
{
//do stuff with col.
}
}

void DoStuff()
{
ICollection<Thing> col = GetThings();
if (col.Length == 0)
{
//do stuff with col.
}
}

void DoStuff()
{
IEnumerable<Thing> col = GetThings();
if (col.Length == 0)
{
//do stuff with col.
}
}

The first can be visually seen to be ok (array has a Length property),
however we can immediately spot the ICollection<T> should be using .Count
and IEnumerable<T> doesn't have Length or Count.

Yes the IDE will highlight these issues with red underlines but you've got
hover over them to see what's actually wrong. As a popular Supermarket in
the UK likes to say "Every little helps".

Note also that this use of var can be a source of bugs. For example perhaps
we started off thinking that GetThings should return ICollection<Thing> but
later choose to return the implementing type instead which perhaps may not
contain all the members from ICollection. If we were using var our code
could be broken, but if we were explicitly using ICollection<Thing>
everything works as before.
 
B

Ben Voigt [C++ MVP]

Var is also useful when dealing with generics, which is why it should
be soon a feature of c++.

In C++0x it is 'auto' (which was already a keyword without a use). And yes,
it's quite preferable to type

auto it = my_map.begin();

instead of

std::map said:
::const_iterator it = my_map.begin();
// careful with the >>>, need whitespace in current version of C++ or else
it misparses
 
C

Christophe Lephay

Anthony Jones said:
I don't agree. To know 'preciseley' what something is when reading a
chunk of code is exactly what a programmer wants.

I agree that if you want to know *exactly* what is really executed, you need
to know the real type. However, i don't think it's such a big requirement if
you want to focus on the algorithm. You could also deduce the type from what
is done with the object.
Consider:-

void DoStuff()
{
var col = GetThings();
if (col.Length == 0)
{
//do stuff with col.
}
}

At glance is col.Length something you can do to col?

I trust the compiler if it says we can...
 
J

J.B. Moreno

Anthony Jones said:
Because in VB6:-

Sub DoStuff(ByVal x as Object)
x.DoMethodOfThing 'Will fail at runtime if object referenced by x does
not have a DoMethodOfThing
End Sub
...
Dim y as Object
Set y = new NotAThing()
DoStuff y ' Oops but only at runtime.

There's no reason to bring VB6 into it, VB9 does the same thing.

And what's the matter with late binding other than the fact that it
doesn't give you intellisence?
 
A

Anthony Jones

J.B. Moreno said:
There's no reason to bring VB6 into it, VB9 does the same thing.

I'm not familiar with VB9. Its Object type behaves the same as VB6? Yikes!
So Object in VB9 isn't the same as System.Object ?
And what's the matter with late binding other than the fact that it
doesn't give you intellisence?

It takes a lot longer (if ever) to discover even the simplest bug such as a
typo in a method name when binding at runtime.
 
J

J.B. Moreno

Anthony Jones said:
I'm not familiar with VB9. Its Object type behaves the same as VB6? Yikes!
So Object in VB9 isn't the same as System.Object ?

It's the same object, the VB compiler uses reflection to extend it's
capabilities. You could get the same results in C# by writing the
reflection code yourself.
It takes a lot longer (if ever) to discover even the simplest bug
such as a typo in a method name when binding at runtime.

I haven't found that to be a problem, particularly for method names --
typo's are found immediately because when using late binding I
immediately test it.

What I have found to be a problem is different string conversions,
where the legacy VB6 class is used, but that's less about late binding
and more about backwards compatibility (well that and the fact that
"ToString" should have been an extension method).
 
A

Anthony Jones

J.B. Moreno said:
It's the same object, the VB compiler uses reflection to extend it's
capabilities. You could get the same results in C# by writing the
reflection code yourself.


I haven't found that to be a problem, particularly for method names --
typo's are found immediately because when using late binding I
immediately test it.

Having to test each modification immediately (with or without the benefit of
Unit Testing) is still orders of magnitude slower than compile time bug
detection. Not to mention that with IDE support such errors are unlikely in
the first place when using staticaly typed variable..
 
J

J.B. Moreno

Anthony Jones said:
Having to test each modification immediately (with or without the benefit of
Unit Testing) is still orders of magnitude slower than compile time bug
detection. Not to mention that with IDE support such errors are unlikely in
the first place when using staticaly typed variable..

I don't know...

VB.NET is a strongly typed language which allows late binding, and so
it is mostly used for COM interop.

Interop is normally limited to just a couple of calls, and while yes,
it takes slightly longer to test than it does to add a reference and
then let the compiler tell you you've got the right method name, it's
not really /that/ much faster.

Now, in code that has been upgraded from VB6, you'll see Object being
used because the VB6 code didn't declare a type (or possibly even the
variable), and there's it a pain, but not because of typos taking
longer to debug. And in C# you won't see that (unless MS comes out
with a VB6 to C# upgrade wizard).
 
A

Anthony Jones

J.B. Moreno said:
I don't know...

VB.NET is a strongly typed language which allows late binding, and so
it is mostly used for COM interop.

Interop is normally limited to just a couple of calls, and while yes,
it takes slightly longer to test than it does to add a reference and
then let the compiler tell you you've got the right method name, it's
not really /that/ much faster.

That realy has to be down to the complexity of your application. If you can
test affected execution path way of your app by simply starting or clicking
a button on its initial form then its just one order of magnitude slower.
However for any serious app some significant effort is required to reach the
affected line.

Also how many such typos is this type of testing going to find in one
execution? One. Then you need to fix it and re-execute or faff with
variable values and code execution points then continue. OTH static types
enable the discovery of nearly all typos in one attempt to compilie
(assuming you didn't notice the red squiggly in the first place).
 
G

Gareth Erskine-Jones

I'm not too immersed in the whole thing but I suspect some people will
really abuse the var keyword instead. My 2 cents is that its better to
declare variables with the right type where possible instead of
scattering var's all over the place. After all you might come back to
your code a few projects later and certainly don't want to figure out
what all those variables of type var do really hold.

This all really comes down to a readability issue. Personally I use
var a lot, and find very few cases when I need to avoid it in order to
increase readability.

I have no trouble reading code like:

var x = new List<string>();

and it certainly looks nicer than

List<string> x = new List<string>();

I'm sure there are cases where confusion could arise, but I think
they're few and far between.

When have you found var confusing?


C#, ASP.NET development and contracting services, London, UK
http://www.sgat-computing-services.co.uk/
 
G

Gareth Erskine-Jones

I fully agree. Smacks too much of "Dim var As Variant" to me...

But that's completely different. The only similarity is the use of the
three character sequence "var".

I've often been told by other programmers that using "var" is lazy and
confusing, some of these people apparently suffered badly in the age
of the Variant. Others seem perfectly aware that var is nothing like
variant, but still don't like it - I don't recall being shown many
examples of where it caused problems or confusion though.


C#, ASP.NET development and contracting services, London, UK
http://www.sgat-computing-services.co.uk/
 
G

Gareth Erskine-Jones

Yes the IDE will highlight these issues with red underlines but you've got
hover over them to see what's actually wrong. As a popular Supermarket in
the UK likes to say "Every little helps".

Hmmm. I don't use hungarian notation because firstly the type checking
provided by most modern compilers catch any errors, which alone I
think is worth avoiding ugly identifiers. Then the IDEs started
highlighting the errors immediately. Yes, I have to hover over
erroneous code to see what's wrong, but I don't find that to be
terribly burdensome.
Note also that this use of var can be a source of bugs. For example perhaps
we started off thinking that GetThings should return ICollection<Thing> but
later choose to return the implementing type instead which perhaps may not
contain all the members from ICollection. If we were using var our code
could be broken, but if we were explicitly using ICollection<Thing>
everything works as before.

I guess it's a matter of taste. I find briefer code easier to read,
and certainly code which avoids duplication (as in the
List<int> i = new List<int>();
declarations) looks unpleasant to me. Again, different strokes for
different folks - with your final example I don't find it particularly
burdensome for the compiler / IDE / Unit Tests to highlight the
problem - and I think the clarity of the code is well worth it.




C#, ASP.NET development and contracting services, London, UK
http://www.sgat-computing-services.co.uk/
 
G

Gareth Erskine-Jones

Frank,

I agree with most, that var should not be used when you know the type
you are working with. I trust the type inference, actually, but it's more
about the readability of the code for me.

Oddly, it's all about the readability of the code for me - and most of
the time I find it more readable with var.


C#, ASP.NET development and contracting services, London, UK
http://www.sgat-computing-services.co.uk/
 
G

Gareth Erskine-Jones

Actually, you never have to figure out the type later - the IDE intellisense
will display the implied type when you hover over the 'var' or over the
variable reference (just as if you had declared the type explicitly) - type
inference works at compile time, not runtime.

That said, I find it very annoying to see 'var' used for trivial cases like
"var i = 2". This just displays a lack of common sense.

Well it certainly doesn't save any characters, but the number of C#
programmers who find that confusing must be vanishingly small. I mean,
most of us know what an int literal looks like don't we?



C#, ASP.NET development and contracting services, London, UK
http://www.sgat-computing-services.co.uk/
 
A

Anthony Jones

Gareth Erskine-Jones said:
Hmmm. I don't use hungarian notation because firstly the type checking
provided by most modern compilers catch any errors, which alone I
think is worth avoiding ugly identifiers. Then the IDEs started
highlighting the errors immediately. Yes, I have to hover over
erroneous code to see what's wrong, but I don't find that to be
terribly burdensome.

I didn't say it was burdensome as implied by my supermarket quote its only a
little thing. However good practice is made up of the cumulative effects of
many little things. Consider that case where there isn't anything wrong but
you are simply reviewing someones code (that someone could be a 6 month
younger version of yourself) again you need to hover over the method to see
the type returned so you can mental match the variable with its type. Again
its only a little thing but on top of that little thing there is another
little thing of remembering that type it was when you stop hovering. Then
you might need to do it for another var (another couple of little things)
and then be able to piece together the exact interactions going on in the
code.

Frankly, using var when the coders knows the specific type the code needs
and the expression on the RHS isn't explicit about the type is lazy coding
and as I pointed can lead to _avoidable_ bugs. The coder should keep in
mind the needs of the human who has to read the code. A chunk of coding in
current developement (like most things) will get read far more often than it
gets written. Use var to shorten the code doesn't necessarily make it more
readable in fact it makes it less readable.

I guess it's a matter of taste. I find briefer code easier to read,
and certainly code which avoids duplication (as in the
List<int> i = new List<int>();
declarations) looks unpleasant to me.

I indicated that this was acceptable earlier in this thread. Since i can
only be a List<int> because the RHS explicitly indicates the type there is
no need to re-state it on the LHS. However my example describes a method
not a new expression. IOW, the above is not a mis-use of var.
Again, different strokes for
different folks - with your final example I don't find it particularly
burdensome for the compiler / IDE / Unit Tests to highlight the
problem - and I think the clarity of the code is well worth it.

You think using var has greater clarity than specifing the exact type
required by the code?? I suspect you are refering to your new expression
example above, in which case you are right but "using var" should be
qualified with "for the right reasons". One could use var whenever a
variable is defined and assigned in the same statement, this would be bad
thing, an abuse of the feature.

As I pointed out the compilier and IDE will not spot a logical error that
can result in the misuse of var. Your unit test is likely to find it but
even that isn't guaranteed. Its still lazy to rely on Unit Tests to find
_avoidable_ bugs.


To summarize, mis-use of var can lead to avoidable bugs and reduces the
clarity of the code. This isn't as subjective as you might like to think.
 
A

Anthony Jones

Gareth Erskine-Jones said:
But that's completely different. The only similarity is the use of the
three character sequence "var".

It also has the characteristic that lexically a specific type is not
demanded of the RHS. It allows the RHS to define the type of the variable
at compile time. Hence the code abdicates the responsibility to define the
type to something outside of the code. This is a bad thing and should only
be used when the type can't be known such as with an anonymous type.
I've often been told by other programmers that using "var" is lazy and
confusing, some of these people apparently suffered badly in the age
of the Variant. Others seem perfectly aware that var is nothing like
variant, but still don't like it - I don't recall being shown many
examples of where it caused problems or confusion though.

Well now you have (see the earlier branch you responded to).
 
A

Anthony Jones

Gareth Erskine-Jones said:
Oddly, it's all about the readability of the code for me - and most of
the time I find it more readable with var.

var can make things more readable when the RHS is explicit about the type it
returns. But when the RHS is not explicit it makes things less readable, it
introduces uncertainty.
 
A

Anthony Jones

Gareth Erskine-Jones said:
This all really comes down to a readability issue. Personally I use
var a lot, and find very few cases when I need to avoid it in order to
increase readability.

I have no trouble reading code like:

var x = new List<string>();

and it certainly looks nicer than

List<string> x = new List<string>();

This is an example of an acceptable usage.
I'm sure there are cases where confusion could arise, but I think
they're few and far between.

There are many cases, all cases where the RHS is _not_ a new expression.

Some are unavoidable:-

var x = new {FirstName = "Fred", LastName = "Flintstone"}

others are avoidable but are not part of the expected idiom:-

var myList = new List<Thing>();

// code to load myList with Things

var e = from x in myList
where x.value == 1
select x

It can be seen that e will be an IEnumerable<Thing> however var is
acceptable in this case since its idomatic to Linq. This is practical since
its common to re-visit and factor Linq statements like this:-

var e = from x in myList
where x.value == 1
select new {foo = x.foo, bar = x.bar}


However things like this:-

var x = externalClass.GetThings();

Can be confusing (what is x) and can be dangerous, the type of x is defined
outside for the current chunk of code.
When have you found var confusing?

Its not confusing, however its misuse is at minimum irritating and at worse
dangerous.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Top