19

When compiling the following program in VS2010, VS2008 or MonoDevelop on Windows, I get warning CS0219, "The variable 'y' is assigned but its value is never used".

namespace Problem
{
    public class Program
    {        
        private static void Main(string[] args)
        {
            object x = new object();
            int y = 0;
        }
    }
}

Why is there no warning for x when compiling in Visual Studio?

Interestingly, I do get CS0219 warnings for x and y when compiling in MonoDevelop on Mac OS X.

Ergwun
  • 12,579
  • 7
  • 56
  • 83

7 Answers7

26

It turns out that this warning is suppressed when the right-hand-side of the assignment operation is not a compile-time constant.

A since-deleted post on Microsoft's Visual Studio feedback site explained that it's because they had lots of complaints from people who were assigning variables purely so they could see what a method call returned during debugging, and found the warning irritating:

The suppression of the "assigned but never used" warning in this case was motivated by feedback from users who do this:

int Blah(){
    // blah
    BlahBlah(x, y, z)
    // blah
    // blah
}

"Hey," says the user while debugging, "I wonder what BlahBlah is returning?" But there is no easy way to examine the return value in the debugger, so users very frequently do this:

int Blah()
{
    // blah
    int temp = BlahBlah(x, y, z)
    // blah
    // blah
}

and then use the locals or watch window to examine temp. The temp is never used anywhere else in the function, so it produced an irritating "assigned but not read" warning.

I think this is a bit of a shame since:

  1. I actually find these warnings helpful when they are given in MonoDevelop.
  2. Anyone can suppress the warning themselves (admittedly they'd also be suppressing the ones for unused compile-time constant assignments - maybe there should be a separate warning for that?).

Anyway, I understand that you can't please everyone.

Ergwun
  • 12,579
  • 7
  • 56
  • 83
  • 4
    Now that you can [view return values in the visual studio debugger](https://msdn.microsoft.com/en-us/library/dn323257.aspx), is there still a reason to have this warning disabled? – pancakes Aug 20 '15 at 20:40
  • 8
    Any way to turn the warning back on? – Xonatron Feb 02 '16 at 22:09
  • 4
    I come here asking if anyone knows how to turn the warning back on...this is because developers are initiating variables that are heavy and not using them (by heavy, I mean instantiating a class that does a lot of things when it's not necessary) – Nelson Rodriguez Aug 03 '16 at 20:36
  • @Xonatron I don't think you can turn it back on in Visual Studio. You may be able to detect it with other code analysis tools such as Resharper (as suggested by RJ Lohan below). – Ergwun Aug 04 '16 at 01:33
  • @NelsonRodriguez (see my comment above) – Ergwun Aug 04 '16 at 01:33
  • The link does not work anymore, but I found an issue for a similar case: https://github.com/dotnet/roslyn/issues/1484. It was closed as "by design". – Andreas Apr 11 '17 at 17:27
  • 2
    "Anyway, I understand that you can't please everyone." it‘s not like options exists that a user could set ¯\\_(ツ)_/¯ – bugybunny Nov 08 '18 at 14:44
  • @bugybunny Fair enough. I'll retreat to the more explicit and easily defensible position that you can't please everyone within the [pragmatic constraints of profitable software development](https://blogs.msdn.microsoft.com/ericlippert/2009/06/22/why-doesnt-c-implement-top-level-methods/). – Ergwun Nov 11 '18 at 08:23
  • 1
    @Ergwun this wasn‘t directed to you, sorry. More a joke that Microsoft could add an option for that if it should generate a warning. – bugybunny Nov 12 '18 at 09:00
  • Actually, in this case you CAN please everyone, by using the same rule most languages use: Don't warn about an unused identifier if it begins with an underscore. Ta-da! Don't even need an option. – Luke Maurer Mar 08 '19 at 00:51
2

I could be off here, but I think it's because y is only set, whereas x is instantiated to something non-trivial - the instantiation could involve separate actions in the New() method, and since instantiating the variable could have side-effects, it's not considered unused. In your case it's just a base object(), so there's no impact, but perhaps the compiler isn't smart enough to tell the difference.

With y, on the other hand, there are no side-effects to the instantiation, so it's considered unused - the application's code path would be unchanged if it were removed entirely.

SqlRyan
  • 33,116
  • 33
  • 114
  • 199
  • 3
    But you could keep the `new object()` call without assigning the result to a variable. – phoog May 15 '12 at 03:06
2

My hunch is that, being x a reference type the compiler does not show any warning since the constructor may be performing some operation that may very well be "meaningful"; in contrast, y being a value type whose value only gets assigned to but never used, it's easy for the compiler to tell you that there's no point in doing this if you are not going to reference it down the line.

Icarus
  • 63,293
  • 14
  • 100
  • 115
  • This makes sense, but you'd think the compiler would know enough to know that a system object like `object` isn't going to have side effects. – Gort the Robot May 15 '12 at 02:55
  • 1
    @StevenBurnap the compiler is not very smart when it comes to "obvious" information like that. Typically that's because the benefit of adding logic to track such things (small) does not outweigh the cost of the compiler's increased complexity (large). – phoog May 15 '12 at 03:00
  • I'm not convinced by this answer. The effects of running the compiler could be preserved thus: `void Main(string[] args) { new object(); int y = 0; }`. – phoog May 15 '12 at 03:04
  • 2
    @StevenBurnap Creating a new `object` *does* have a side effect: it allocates memory. If nothing else, it generates memory pressure -- which might well have been your intent. No way is the compiler going to "know" that there are "no side effects" when there *are* side effects. – Joe White May 15 '12 at 03:10
  • My previous comment should read "... the effects of running the constructor ...", not "compiler"! – phoog May 15 '12 at 03:19
1

ReSharper will also warn you that x is unused.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
RJ Lohan
  • 6,497
  • 3
  • 34
  • 54
0

It could be that since x is a reference type, and is thus stored on the heap, that it would prevent garbage collection of that object until x goes out of scope.

For example:

void main(string[] args)
{
    object x = new object();
    while (true)
    {
        // Some threading stuff
        // x is never garbage collected
    }
}

In contrast to:

void main(string[] args)
{
    new object();
    while (true)
    {
        // Some threading stuff
        // The unreferenced object IS garbage collected
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Matthew
  • 24,703
  • 9
  • 76
  • 110
  • 1
    AFAIK that only applies if you're running in the debugger, in which case the runtime extends the liveness range of locals to the whole method. In release mode, they can be much shorter - or in this case eliminated entirely. – Mikayla Hutchinson May 15 '12 at 07:18
0

y is on the stack, x is on the heap (clue: x uses the new keyword). So some debugger/compiler warnings probably consider the heap/global variables like x to be left to the programmer to worry about, since low-level code or a debug probe might be playing with them behind the scenes. But a stack variable like y is totally under the compiler's control and will easily be able to provably-detect an unused redundant variable.

Gregory Fenn
  • 460
  • 2
  • 13
-1

Eclipse will consider the case unused.

user1112699
  • 197
  • 3