VisualStudio2008 strange of compiler warning, explanation needed - c#

Just a quick Question to the compiler of VisualStudio 2008.
We do have enabled that compiler-warnings are treated as errors which works fine, but today i recognized, that following behaviour:
static void Main(string[] args)
{
int number = 0;
DateTime dateTime = DateTime.Now;
}
Compiling this snippet results in only one warning: "The variable 'number' is assigned, but its value is never used".
Can anyone explain the difference to me, why the variable number results to the error, but not the dateTime variable?
Ok, it seems it has something to do with literals. Taking the following code in account:
static void Main(string[] args)
{
string str1 = "Foo";
string str2 = str1;
}
Compiling with both lines leads to no warning, although the variable "str2" is never referenced. If you comment out the line string str2 = str1; the warning shows up for variable "str1" is never used.

It is because DateTime.Now is a property, not a literal. Property getters can have side-effects, simply calling one can be useful by itself. Not that this is a good idea, it is however not verboten to do so and the compiler isn't smart enough to tell whether or not it does. It can't anyway, it ultimately calls operating system code to obtain the current system time.

My guess is that the statement int number = 0; is completely side-effect free and can be identified as superfluous by the compiler. DateTime dateTime = DateTime.Now; on the other hand, is an evaluation of a static property and could potentially execute other code, thus compiler does not identify it as an unused variable. In other words, while the variable might be unused, the act of assigning it could potentially do something else.

Eric Lippert wrote an article on this, so I'll leave it to him to explain:
Normally C# warns on all variables and
fields which are never read, never
written, etc. But in this case we
suppress the warning on purpose if the
assignment is not a constant
expression.
This is because there is no good way
in the Visual Studio debugger to say
"show me the return value of the last
function call". Though I would agree
were you to sensibly point out that
the way to solve this is to fix the
debugger, given that I have no ability
to fix it, we need a solution in C#
for our customers.
See article for further explanation.

DateTime.Now is a reference. I might be wrong since i have no experience with C# but i don't think you're creating a new object when using DateTime.Now.

Related

Why can I apply a null-conditional operator to a hardcoded string?

I have a bool variable like this:
bool myBool = true;
If I write if (myBool == null) I get the following warning:
The result of the expression is always 'false' since a value of type 'bool' is never equal to 'null' of type 'bool?'.
That's clear to me because it doesn't make sense to check whether a non-nullable variable is null. Visual Studio notices that and marks as warning.
Now I have a string, which is nullable by default, as I know.
Why can I apply a null-conditional operator to a hardcoded string without Visual Studio noticing it? I'm thinking of something like this:
"This is a string"?.AnyStringMethod();
Shouldn't Visual Studio notice that this string isn't null at all?
Warnings are for code that looks right but is actually wrong.
Your code looks wrong but does the right thing anyways.
Therefore: no warning.
Visual Studio must go off the type that the operator is working with.
When you create a bool, there is no way that it could ever be null by the type, until you change that type to bool?.
However, with a hard coded string, even though it has text within the quotes, there's no guarantee that it will stay there. The "variable" that gets created (even as just a plain string) is still of type string, which is able to have a null assigned to it and not change the type.
What you are looking for would be for them to inspect the value of every variable that they are creating. If they were to do that, then why not also check for something like this?
var i = 0;
if (i > 2) // This will always be false!
Update
As InBetween mentioned in the comments, there is a bit of an oversight in here as well. Having a string such as "Some string" that is not assigned in a variable is functionally equivalent to const string s = "Some string";. If you were to declare it like that, the code inspectors will detect if you run a comparison on that, such as the following:
const string s = "Some String";
if (s == null) // This will give a warning that this can't happen
I would attribute that difference in the way that the const is handled versus the way a plain static string is handled could be attributed to different development teams working on different parts at different times. Again, this is such an edge case that doesn't cause huge problems that it doesn't get warned that no one working on it most likely didn't think about it.
Because no one thought about it? Your code is so pointless that probably no one foresaw it would ever be used in production code. I'm pretty sure this scenario didn't even crop up once in the C# design comittees although I'd take that with a grain of salt until someone like Eric Lippert sheds more light on the issue.
C# sharp isn't born with all potential features and then someone decides to prune it. In order for the compiler to give a certain warning someone has to think about it, implement it, test it and document it.
In case of myBool == null, the warning is justified becuase its a plausible error that could potentially make it into production code and its clearly a bug in the program's logic. The second scenario is completely harmless even if it ends up making it into production, so the warning really doesn't make much sense.
Because bool is of a value type while string is a reference type
Value types cannot be null, but reference types are automaticly nulled through Default
The reason Visual Studio doesn´t notice, is because it is of no importancable really.. it is like asking if blue is more of a color than green
A string literal is slightly different than a string object. I believe the string literal is basically like a constant, it is immutable, and will not ever be null.
When you assign a string literal to a variable, you are creating a reference to the string in a memory location. That reference can be null. If you try to concatenate your string variable with another string and store back in your original string variable, the original string in memory is destroyed and a new string is created that is the concatenated string. This is because strings are always immutable.

Variable is assigned but its value is never used (C#)

In Visual Studio I used the following code:
private bool answer = true;
Private Buttonclick()
{
if()
{
answer =false
}
}
Compiler gives me a warning that says "answer is assigned but its value is never used".
How do I fix this?
It means you have given answer a value, but not referenced it elsewhere. Meaning you are not using answer elsewhere in your program.
You fix it by referencing answer from another part of your program.
The reason the warning pops up is not because the variable is never assigned, but because it is in fact never used for any sort of comparison in the rest of the code.
Please go through this reference:
http://weblog.west-wind.com/posts/2009/Feb/28/Variable-is-assigned-but-its-Value-is-never-used-Warning
If you want to disable warnings, the error list contains a button that can stop them being shown in the list.
Additionally, a warning is just a warning. They won't stop your program from compiling, or even running. They may, however, declare in advance runtime errors and the like, so don't ignore them completely.
In addition to the answers above, for more deep understanding of the this warning:
This warning will not always pop-up (if you not use assigned variable). Assigning a non-constant expression or method result will NOT generate the warning. It is done intentionally, since such an unassigned variables can be used in debugging.
For example:
var answer = SomeObject.SomePropery; //will not generate CS0219
There are excellent explanation in Microsoft.Docs:
https://learn.microsoft.com/en-us/dotnet/csharp/misc/cs0219

About unassigned variables

Just curious, I'm not trying to solve any problem.
Why only local variables should be assigned?
In the following example:
class Program
{
static int a;
static int b { get; set; }
static void Main(string[] args)
{
int c;
System.Console.WriteLine(a);
System.Console.WriteLine(b);
System.Console.WriteLine(c);
}
}
Why a and b gives me just a warning and c gives me an error?
Addionally, why I can't just use the default value of Value Type and write the following code?
bool MyCondition = true;
int c;
if (MyCondition)
c = 10;
Does it have anything to do with memory management?
Tim gives a good answer to your first question but I can add a few more details.
Your first question is basically "locals are required to be definitely assigned, so why not make the same restriction on fields?" Tim points out that Jon points out that it is actually quite difficult to do so. With locals it is almost always crystal clear when a local is first read and when it is first written. In the cases where it is not clear, the compiler can make reasonable conservative guesses. But with fields, to know when a first read and a first write happens, you have to know all kinds of things about which methods are called in what order.
In short, analyzing locals requires local analysis; the analysis doesn't have to go past the block that contains the declaration. Field analysis requires global analysis. That's a lot of work; it's easier to just say that fields are initialized to their default values.
(Now, that said, it is of course possible to do this global analysis; my new job will likely involve doing precisely this sort of analysis.)
Your second question is basically "Well then, if automatic assignment of default values is good enough for fields then why isn't it good enough for locals?" and the answer is "because failing to assign a local variable and accidentally getting the default value is a common source of bugs." C# was carefully designed to discourage programming practices that lead to irritating bugs, and this is one of them.
Because other variables are initialized with their default value.
Jon Skeet has already found some interesting words on this issue:
For local variables, the compiler has a good idea of the flow - it can
see a "read" of the variable and a "write" of the variable, and prove
(in most cases) that the first write will happen before the first
read.
This isn't the case with instance variables. Consider a simple
property - how do you know if someone will set it before they get it?
That makes it basically infeasible to enforce sensible rules - so
either you'd have to ensure that all fields were set in the
constructor, or allow them to have default values. The C# team chose
the latter strategy.
and here's the related C# language specification:
5.3 Definite assignment
At a given location in the executable code of a function member, a
variable is said to be definitely assigned if the compiler can prove,
by a particular static flow analysis (§5.3.3), that the variable has
been automatically initialized or has been the target of at least one
assignment.
5.3.1 Initially assigned variables
The following categories of variables are classified as initially
assigned:
Static variables.
Instance variables of class instances.
Instance variables of initially assigned struct variables.
Array elements.
Value parameters.
Reference parameters.
Variables declared in a catch clause or a foreach statement.
5.3.2 Initially unassigned variables
The following categories of variables are classified as initially
unassigned:
Instance variables of initially unassigned struct variables.
Output parameters, including the this variable of struct instance
constructors.
Local variables, except those declared in a catch clause or a
foreach statement.
The CLR provides a hard guarantee that local variables are initialized to their default value. But this guarantee does have limitations. What is missing is its ability to recognize scope blocks inside the method body. They disappear once the compiler translates the code to IL. Scope is a language construct that doesn't have a parallel in the CLI and cannot be expressed in IL.
You can see this going wrong in a language like VB.NET for example. This contrived example shows the behavior:
Module Module1
Sub Main()
For ix = 1 To 3
Dim s As String
If ix = 2 Then s = "foo"
If s Is Nothing Then Console.WriteLine("null") Else Console.WriteLine(s)
Next
Console.ReadLine()
End Sub
End Module
Output:
null
foo
foo
Or in other words, the local variable s was initialized only once and retains its value afterwards. This has a knack for creating bugs of course. The VB.NET compiler does generate a warning for it and has simple syntax to avoid it (As New). A managed language like C++/CLI has the same behavior but doesn't emit a diagnostic at all. But the C# language gives a stronger guarantee, it generates an error.
This rule is called "definite assignment". The exact rules are explained in detail in the C# Language Specification, chapter 5.3.3
Definite assignment checking has its limitations. It works well for local variables since their scope is very limited (private to the method body) and you can't get to them with Reflection. Much harder to do with fields of a class, it requires whole-program analysis that may need to reach beyond what the compiler can see. Like code in another assembly. Which is why the C# compiler can only warn about it but can't reject the code out-right.

Use of "var" type in variable declaration

Our internal audit suggests us to use explicit variable type declaration instead of using the keyword var. They argue that using of var "may lead to unexpected results in some cases".
I am not aware of any difference between explicit type declaration and using of var once the code is compiled to MSIL.
The auditor is a respected professional so I cannot simply refuse such a suggestion.
How about this...
double GetTheNumber()
{
// get the important number from somewhere
}
And then elsewhere...
var theNumber = GetTheNumber();
DoSomethingImportant(theNumber / 5);
And then, at some point in the future, somebody notices that GetTheNumber only ever returns whole numbers so refactors it to return int rather than double.
Bang! No compiler errors and you start seeing unexpected results, because what was previously floating-point arithmetic has now become integer arithmetic without anybody noticing.
Having said that, this sort of thing should be caught by your unit tests etc, but it's still a potential gotcha.
I tend to follow this scheme:
var myObject = new MyObject(); // OK as the type is clear
var myObject = otherObject.SomeMethod(); // Bad as the return type is not clear
If the return type of SomeMethod ever changes then this code will still compile. In the best case you get compile errors further along, but in the worst case (depending on how myObject is used) you might not. What you will probably get in that case is run-time errors which could be very hard to track down.
Some cases could really lead to unexpected results. I'm a var fan myself, but this could go wrong:
var myDouble = 2;
var myHalf = 1 / myDouble;
Obviously this is a mistake and not an "unexpected result". But it is a gotcha...
var is not a dynamic type, it is simply syntactic sugar. The only exception to this is with Anonymous types. From the Microsoft Docs
In many cases the use of var is optional and is just a syntactic convenience. However, when a variable is initialized with an anonymous type you must declare the variable as var if you need to access the properties of the object at a later point.
There is no difference once compiled to IL unless you have explicitly defined the type as different to the one which would be implied (although I can't think of why you would). The compiler will not let you change the type of a variable declared with var at any point.
From the Microsoft documentation (again)
An implicitly typed local variable is strongly typed just as if you had declared the type yourself, but the compiler determines the type
In some cases var can impeed readability. More Microsoft docs state:
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.
In the non-generic world you might get different behavior when using var instead of the type whenever an implicit conversion would occur, e.g. within a foreach loop.
In the example below, an implicit conversion from object to XmlNode takes place (the non-generic IEnumerator interface only returns object). If you simply replace the explicit declaration of the loop variable with the var keyword, this implicit conversion no longer takes place:
using System;
using System.Xml;
class Program
{
static void Foo(object o)
{
Console.WriteLine("object overload");
}
static void Foo(XmlNode node)
{
Console.WriteLine("XmlNode overload");
}
static void Main(string[] args)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml("<root><child/></root>");
foreach (XmlNode node in doc.DocumentElement.ChildNodes)
{
Foo(node);
}
foreach (var node in doc.DocumentElement.ChildNodes)
{
// oops! node is now of type object!
Foo(node);
}
}
}
The result is that this code actually produces different outputs depending on whether you used var or an explicit type. With var the Foo(object) overload will be executed, otherwise the Foo(XmlNode) overload will be. The output of the above program therefore is:
XmlNode overload
object overload
Note that this behavior is perfectly according to the C# language specification. The only problem is that var infers a different type (object) than you would expect and that this inference is not obvious from looking at the code.
I did not add the IL to keep it short. But if you want you can have a look with ildasm to see that the compiler actually generates different IL instructions for the two foreach loops.
It's an odd claim that using var should never be used because it "may lead to unexpected results in some cases", because there are subtleties in the C# language far more complex than the use of var.
One of these is the implementation details of anonymous methods which can lead to the R# warning "Access to modified closure" and behaviour that is very much not what you might expect from looking at the code. Unlike var which can be explained in a couple of sentences, this behaviour takes three long blog posts which include the output of a disassembler to explain fully:
The implementation of anonymous methods in C# and its consequences (part 1)
The implementation of anonymous methods in C# and its consequences (part 2)
The implementation of anonymous methods in C# and its consequences (part 3)
Does this mean that you also shouldn't use anonymous methods (i.e. delegates, lambdas) and the libraries that rely on them such as Linq or ParallelFX just because in certain odd circumstances the behaviour might not be what you expect?
Of course not.
It means that you need to understand the language you're writing in, know its limitations and edge cases, and test that things work as you expect them to. Excluding language features on the basis that they "may lead to unexpected results in some cases" would mean that you were left with very few language features to use.
If they really want to argue the toss, ask them to demonstrate that a number of your bugs can be directly attributed to use of var and that explicit type declaration would have prevented them. I doubt you'll hear back from them soon.
They argue that using of var "may lead
to unexpected results in some cases".to unexpected results in some cases".
If unexpected is, "I don't know how to read the code and figure out what it is doing," then yes, it may lead to unexpected results. The compiler has to know what type to make the variable based on the code written around the variable.
The var keyword is a compile time feature. The compiler will put in the appropriate type for the declaration. This is why you can't do things like:
var my_variable = null
or
var my_variable;
The var keyword is great because, you have to define less information in the code itself. The compiler figures out what it is supposed to do for you. It's almost like always programming to an interface when you use it (where the interface methods and properties are defined by what you use within the declaration space of the variable defined by var). If the type of a variable needs to change(within reason of course), you don't need to worry about changing the variable declaration, the compiler handles this for you. This may sound like a trivial matter, but what happens if you have to change the return value in a function, and that function is used all throughout the program. If you didn't use var, then you have to find and replace every place that variable is called. With the var keyword, you don't need to worry about that.
When coming up with guidelines, as an auditor has to do, it is probably better to err on the side of fool safe, that is white listing good practices / black listing bad practices as opposed to telling people to simply be sensible and do the right thing based on an assessment of the situation at hand.
If you just say "don't use var anywhere in code", you get rid of a lot of ambiguity in the coding guidelines. This should make code look & feel more standardized without having to solve the question of when to do this and when to do that.
I personally love var. I use it for all local variables. All the time. If the resulting type is not clear, then this is not an issue with var, but an issue with the (naming of) methods used to initialize a variable...
I follow a simple principle when it comes to using the var keyword. If you know the type beforehand, don't use var.
In most cases, I use var with linq as I might want to return an anonymous type.
var best using when you have obviously declaration
ArrayList<Entity> en = new ArrayList<Enity>()
complicates readability
var en = new ArrayList<Entity>()
Lazy, clear code, i like it
I use var only where it is clear what type the variable is, or where it is no need to know the type at all (e.g. GetPerson() should return Person, Person_Class, etc.).
I do not use var for primitive types, enum, and string. I also do not use it for value type, because value type will be copied by assignment so the type of variable should be declared explicitly.
About your auditor comments, I would say that adding more lines of code as we have been doing everyday also "lead to unexpected results in some cases". This argument validity has already proven by those bugs we created, therefore I would suggest freezing the code base forever to prevent that.
using var is lazy code if you know what the type is going to be. Its just easier and cleaner to read. When looking at lots and lots of code, easier and cleaner is always better
There is absolutely no difference in the IL output for a variable declaration using var and one explicitly specified (you can prove this using reflector). I generally only use var for long nested generic types, foreach loops and anonymous types, as I like to have everything explicitly specified. Others may have different preferences.
var is just a shorthand notation of using the explicit type declaration.
You can only use var in certain circumstances; You'll have to initialize the variable at declaration time when using var.
You cannot assign a variable that is of another type afterwards to the variable.
It seems to me that many people tend to confuse the 'var' keyword with the 'Variant' datatype in VB6 .
The "only" benefit that i see towards using explicit variable declaration, is with well choosen typenames you state the intent of your piece of code much clearer (which is more important than anything else imo). The var keyword's benefit really is what Pieter said.
I also think that you will run into trouble if you declare your doubles without the D on the end. when you compile the release version, your compiler will likely strip off the double and make them a float to save space since it will not consider your precision.
var will compile to the same thing as the Static Type that could be specified. It just removes the need to be explicit with that Type in your code. It is not a dynamic type and does not/can not change at runtime. I find it very useful to use in foreach loops.
foreach(var item in items)
{
item.name = ______;
}
When working with Enumerations some times a specific type is unknown of time consuming to lookup. The use of var instead of the Static Type will yeald the same result.
I have also found that the use of var lends it self to easier refactoring. When a Enumeration of a different type is used the foreach will not need to be updated.
Use of var might hide logical programming errors, that otherwise you would have got warning from the compiler or the IDE. See this example:
float distX = innerDiagramRect.Size.Width / (numObjInWidth + 1);
Here, all the types in the calculation are int, and you get a warning about possible loss of fraction because you pick up the result in a float variable.
Using var:
var distX = innerDiagramRect.Size.Width / (numObjInWidth + 1);
Here you get no warning because the type of distX is compiled as int. If you intended to use float values, this is a logical error that is hidden to you, and hard to spot in executing unless it triggers a divide by zero exception in a later calculation if the result of this initial calculation is <1.

Why can’t down-casting be checked at compile time?

Why can’t compiler detect at compile-time that obj references object of type B and thus reports an error when we try to cast it to type A?
public class A { }
public class B { }
static void Main(string[] args)
{
B b = new B();
object obj = (object)b;
A a = (A)obj; // exception
thanx
Because of the Halting problem. This essentially means that you cannot decide which execution path will the program follow (and there is a mathematical proof for that). For example the following code may or may not be correct:
object o = SomeTest() ? (new A()) : (new B());
A a = (A)o;
If the SomeTest method always returns true then it is correct. Unfortunatelly, it is not possible to decide that. However, there is a lot of research going on in this field. Even though it cannot be always checked, there are tools that can sometimes verify that something will always succeed or give you an example of execution path for which the assumption fails.
A good example of this technique are Code Contracts, which will be a part of Visual Studio 2010. I believe you could use them to give prove that your down-casting will be correct. However, there is no explicit support for this - although, it would be useful!
Let me turn the question around: if the compiler could prove that, then why would we need casts at all? The purpose of a cast is tell the compiler "I know more about this code than you do, and I promise you that this cast is valid. I am so sure of that fact that I am willing to let you generate code that throws an exception if I'm wrong." The compiler can't prove that the cast is valid precisely because the cast is for scenarios where the compiler can't prove that it is valid.
A compiler certainly could implement checks that would work in trivial cases like this. But doing so would be unlikely to help "real" code very much, since programmers rarely write such obviously wrong code.
To handle more complicated cases, a compiler would have to perform much more complicated analysis. This is harder for the compiler writer to do, and is also slower for your machine to run, and it still wouldn't be able to catch every possible bad cast. And again, because most code doesn't have easily-identifiable errors of this sort, it's not clear that the payoff would be worth the cost of writing the analysis.
Two drawbacks of more complicated static analysis are error messages and false positives. First, having a tool explain a problem in code is often an order of magnitude harder than having the tool merely check for the problem. Second, as checked-for problems turn from "bad thing X will definitely happen" to "bad thing Y might happen", it becomes much more likely that the tool will flag things that aren't ever a problem in practice.
There's an interesting essay written by a company, selling static analysis tools, that was spun off from academic research. One thing they discovered is that they often made fewer sales with more complicated analyses! A Few Billion Lines of Code Later: Using Static Analysis to Find Bugs in the Real World
You want the compiler to follow the control flow, and determine ahead of time that the cast will cause an exception? Why bother? With a real program, the control flow will be too complicated to figure this out.
Even static analysis tools wouldn't be able to solve this problem. What if your code uses reflection?
void Test(string typeName)
{
Type t = Type.GetType(typeName);
object obj = Activator.CreateInstance(t);
A a = (A)obj;
// etc.
}
Will this throw an exception? There is absolutely no possible way to know the answer without actually running it. No amount of code-path analysis will unravel a bug that depends on the value of some particular parameter. And if you have to run the code to detect the bug, then that makes it a runtime error, not compile-time.
This is exactly the reason why you need to test your code. Compilers can't ensure that your code is correct, only that it's syntactically valid and follows whatever rules are in the grammar.
And although this might seem like a contrived example, reflection is used pretty much everywhere these days, from your O/R mapper to your DI framework. It's actually quite common in a modern application not to know the type of some instance, or at least not the specific concrete type, until runtime.
Because you'd sit there for days while compilers tried every possible path through your code.
As others have mentioned, the general problem is that the compiler would have to trace back through all possible execution paths to see where that variable may have come from - and then determine if the cast is valid.
Imagine if the object was passed in to the function, which then downcast it. The compiler would have to know the run-time type of the object passed in. The calling code may not even exist at compile time, if this is a library.
In a basic example like yours, one might think it would be easy for a compiler to intelligently look for all references to a particular object and then see if it's being illegally cast. But consider this counterexample:
public class A { }
public class B { }
static void Main(string[] args)
{
B b = new B();
object obj = (object)b;
// re-using the obj reference
obj = new A();
A a = (A)obj; // cast is now valid
There are so many possible permutations of ways you could re-use and cast a particular base reference that a compiler writer would need to foresee. It gets even more complicated when the obj reference is passed in a parameter to a method. Compile-time checking becomes non-deterministic, making compilations times potentially much longer and still not guaranteeing it would be able to catch all invalid casts.

Categories

Resources