28

I created a "const" for a value previously explicitly stated several times in my code:

private static readonly int QUARTER_HOUR_COUNT = 96;

When I did a search-and-replace of 96 for QUARTER_HOUR_COUNT, I inadvertently also replaced the declaration, so it became:

private static readonly int QUARTER_HOUR_COUNT = QUARTER_HOUR_COUNT;

...yet it compiled. I would think that it would disallow that. Why was it accepted by the compiler as a valid declaration?

B. Clay Shannon-B. Crow Raven
  • 8,547
  • 144
  • 472
  • 862

5 Answers5

23

I would think that it would disallow that. Why was it accepted by the compiler as a valid declaration?

Presumably because the language specification allows it. Do you have a specific rule in the language specification which you think prohibits it?

If your question is really "why doesn't the language specification prohibit this" - I suspect it's because it's probably quite hard to make sure you only prohibit things you really want to prohibit, while actually prohibit all such things.

You could argue that for simple cases of assignment directly back to itself, it would be good to have a special case in the language spec, but it would introduce complexity into the language for relatively little benefit.

Note that even if you didn't get an error, I'd expect you to get a warning - something like this:

Test.cs(3,33): warning CS1717: Assignment made to same variable; did you mean to assign something else?

Also note that if you make it a const instead of just a static readonly variable, then you do get a compile-time error:

Test.cs(3,23): error CS0110: The evaluation of the constant value for 'Program.QUARTER_HOUR_COUNT' involves a circular definition

Also note that by .NET naming conventions, this ought to be called QuarterHourCount, rather than having a SHOUTY_NAME.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    Usage of unassigned variable I would have thought. – leppie Aug 15 '12 at 16:28
  • 3
    @leppie: Not for static fields in a static field initializer. The term "Unassigned variable" is irrelevant for static fields, which have no concept of definite assignment. – Jon Skeet Aug 15 '12 at 16:29
  • Actually there is, they are initialized in the order they are defined. This IMO breaks that rule. – leppie Aug 15 '12 at 16:31
  • @leppie They are all initialized after they are all defined (in the order that they were initially defined). – Servy Aug 15 '12 at 16:32
  • 1
    @leppie: There's an initialization order, but no concept of "unassigned variable" which is different. If you believe it actually violates a rule, can you point out the exact section of the spec you believe it violates? – Jon Skeet Aug 15 '12 at 16:32
  • 1
    @JonSkeet: Interesting ;p We have a hidden Y combinator! eg `static Func f = x => (x == 0) ? x : f(x-1);` – leppie Aug 15 '12 at 16:36
  • @leppie: That would always capture `f` *at the point of execution* anyway. – Jon Skeet Aug 15 '12 at 16:41
  • @JonSkeet: But the syntax would not be allowed otherwise ;p – leppie Aug 15 '12 at 16:43
  • @leppie: Well, it depends on what the rule was. That wouldn't work for local variables of course, but I could imagine a rule which would prohibit the OP's code but not your Y-combinator. – Jon Skeet Aug 15 '12 at 16:44
  • 6
    @Jon: Yes, I did get that warning msg, but I didn't see it, as (at least in the way I've got VS set up) it doesn't display unless I explicitly look for it via View | Error List. As to the "shouty" name, I realize this is a controversial topic, and I certainly respect your opinion, but that is one of the stylistic trends I buck, because I find the "shouty" nomenclature easier to grok as I scan through the code; IOW, shouty == constants or "pseudo-constants" (readonly static) – B. Clay Shannon-B. Crow Raven Aug 15 '12 at 17:01
  • 1
    @ClayShannon: This is a good reason to treat warnings as errors :) It's pretty easy to go warning-free in C#. As far as the conventions go - within "private" code that's okay, but I'd strongly advise you to follow conventions if you make the code public (e.g. an open source project). – Jon Skeet Aug 15 '12 at 17:47
6

The IL code generated by the code is this:

 IL_0007:  ldsfld     int32 Example.Quat::QUARTER_HOUR_COUNT//Load the value of a static field on the stack
 IL_000c:  stsfld     int32 Example.Quat::QUARTER_HOUR_COUNT// Store the value from the stack in the static field

Since the default value of QUARTER_HOUR_COUNT is 0,the 0 is assigned to QUARTER_HOUR_COUNT

Anirudha
  • 32,393
  • 7
  • 68
  • 89
5

Because the variable was initialized as 0 and then set to itself.

My guess would be that it would be doing a new Int() prior to setting to itself which would initialize it to zero.

tsells
  • 2,751
  • 1
  • 18
  • 20
4

Because the compiler will break this line down:

private static readonly int QUARTER_HOUR_COUNT = QUARTER_HOUR_COUNT;

Basically into the IL equivalent of:

private static readonly int QUARTER_HOUR_COUNT;
QUARTER_HOUR_COUNT = QUARTER_HOUR_COUNT;

And then obviously that'll get broken down more too, but the above should suffice to illustrate my point.

So technically it'll exist with a default value of zero at the time it gets used.

Phillip Schmidt
  • 8,805
  • 3
  • 43
  • 67
0

As others have implied value types like int have a default value so declaring a variable without explicitly initializing it means it still has a value.

You can find out the default value for any type like so:

int i = default(int);

Or more generally:

T t = default(T);

Note that for reference types the default will be null, only value types will have default values.

RobV
  • 28,022
  • 11
  • 77
  • 119