Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. Compiler issue?

Compiler issue?

Scheduled Pinned Locked Moved C#
helpquestion
11 Posts 2 Posters 1 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • C Offline
    C Offline
    Chadwick Posey
    wrote on last edited by
    #1

    Here's an interesting one -- Can someone riddle me this? Given: using System; enum Foo { Bar, None } class Program { static void PrintArg(object x) { Console.WriteLine(x.ToString()); } static void PrintArg(Foo x) { Console.WriteLine(x.ToString()); } public static void Main() { PrintArg(Foo.None); PrintArg(0); PrintArg(1); } } Results in the output of:

    None
    Bar
    1

    Note: The application of this issue is apparent in the SqlParameter constructors -- If you do SqlParameter param = new SqlParameter("Name", 0); it calls the SqlDbType override, instead of the object value override. Any ideas why the int 0 isn't acting like the int 1? Is 0 not an int by default? Chadwick

    ============================= I'm a developer, he's a developer, she's a developer, Wouldn'tcha like to be a developer too?

    J 1 Reply Last reply
    0
    • C Chadwick Posey

      Here's an interesting one -- Can someone riddle me this? Given: using System; enum Foo { Bar, None } class Program { static void PrintArg(object x) { Console.WriteLine(x.ToString()); } static void PrintArg(Foo x) { Console.WriteLine(x.ToString()); } public static void Main() { PrintArg(Foo.None); PrintArg(0); PrintArg(1); } } Results in the output of:

      None
      Bar
      1

      Note: The application of this issue is apparent in the SqlParameter constructors -- If you do SqlParameter param = new SqlParameter("Name", 0); it calls the SqlDbType override, instead of the object value override. Any ideas why the int 0 isn't acting like the int 1? Is 0 not an int by default? Chadwick

      ============================= I'm a developer, he's a developer, she's a developer, Wouldn'tcha like to be a developer too?

      J Offline
      J Offline
      joon vh
      wrote on last edited by
      #2

      this is hilarious :p

              enum Foo { Bar, None }
      
              static void PrintArg(object x) { Console.WriteLine(x.ToString()); }
              static void PrintArg(Foo x) { Console.WriteLine(x.ToString()); }
              public static void Main()
              {
                  PrintArg(Foo.None);
                  PrintArg(Convert.ToInt32(0.ToString()));
                  PrintArg(1);
              }
      

      your problem is very strange :) here's the output when you cast it to int, Int32, ...

      PrintArg(0); //bar
      PrintArg((int)0); //bar
      PrintArg((Int16)0); //0
      PrintArg((Int32)0); //bar
      PrintArg((Int64)0); //0

      -- modified at 14:16 Wednesday 21st March, 2007 -- modified at 14:17 Wednesday 21st March, 2007


      Visual Studio can't evaluate this, can you? public object moo { __get { return moo; } __set { moo = value; } }

      C 1 Reply Last reply
      0
      • J joon vh

        this is hilarious :p

                enum Foo { Bar, None }
        
                static void PrintArg(object x) { Console.WriteLine(x.ToString()); }
                static void PrintArg(Foo x) { Console.WriteLine(x.ToString()); }
                public static void Main()
                {
                    PrintArg(Foo.None);
                    PrintArg(Convert.ToInt32(0.ToString()));
                    PrintArg(1);
                }
        

        your problem is very strange :) here's the output when you cast it to int, Int32, ...

        PrintArg(0); //bar
        PrintArg((int)0); //bar
        PrintArg((Int16)0); //0
        PrintArg((Int32)0); //bar
        PrintArg((Int64)0); //0

        -- modified at 14:16 Wednesday 21st March, 2007 -- modified at 14:17 Wednesday 21st March, 2007


        Visual Studio can't evaluate this, can you? public object moo { __get { return moo; } __set { moo = value; } }

        C Offline
        C Offline
        Chadwick Posey
        wrote on last edited by
        #3

        So what we're trying to say is that 0 cannot be implicitly boxed by a call to a method if it is in an Int32 valuetype, but it can be boxed if its in an Int16 or an Int64? Any CLR specialists care to take a stab at this one? Anyone try this targeting .NET 1.1? Mine is targeting 2.0... Btw if you call the method as (object)0 -- it outputs 0 as expected. I also use Resharper, and when I do a (object)1 it tells me the cast is redundant, but when I do a (object)0, it does not!

        ============================= I'm a developer, he's a developer, she's a developer, Wouldn'tcha like to be a developer too?

        J 2 Replies Last reply
        0
        • C Chadwick Posey

          So what we're trying to say is that 0 cannot be implicitly boxed by a call to a method if it is in an Int32 valuetype, but it can be boxed if its in an Int16 or an Int64? Any CLR specialists care to take a stab at this one? Anyone try this targeting .NET 1.1? Mine is targeting 2.0... Btw if you call the method as (object)0 -- it outputs 0 as expected. I also use Resharper, and when I do a (object)1 it tells me the cast is redundant, but when I do a (object)0, it does not!

          ============================= I'm a developer, he's a developer, she's a developer, Wouldn'tcha like to be a developer too?

          J Offline
          J Offline
          joon vh
          wrote on last edited by
          #4

          this is at least a 7 on the WTF-scale.


          Visual Studio can't evaluate this, can you? public object moo { __get { return moo; } __set { moo = value; } }

          C 1 Reply Last reply
          0
          • C Chadwick Posey

            So what we're trying to say is that 0 cannot be implicitly boxed by a call to a method if it is in an Int32 valuetype, but it can be boxed if its in an Int16 or an Int64? Any CLR specialists care to take a stab at this one? Anyone try this targeting .NET 1.1? Mine is targeting 2.0... Btw if you call the method as (object)0 -- it outputs 0 as expected. I also use Resharper, and when I do a (object)1 it tells me the cast is redundant, but when I do a (object)0, it does not!

            ============================= I'm a developer, he's a developer, she's a developer, Wouldn'tcha like to be a developer too?

            J Offline
            J Offline
            joon vh
            wrote on last edited by
            #5

            try

            PrintArg(-0);

            and

            Console.WriteLine(0.GetType() == 1.GetType());

            and the resharper making it redundant is _very_ odd to say the least. I use it too. It usually looks up whether your type cast has any purpose for this specific case. f.e. casting 0 into object for the purpose of .GetType'ing makes it redundant, because it also has this option without the cast.


            Visual Studio can't evaluate this, can you? public object moo { __get { return moo; } __set { moo = value; } }

            C 1 Reply Last reply
            0
            • J joon vh

              this is at least a 7 on the WTF-scale.


              Visual Studio can't evaluate this, can you? public object moo { __get { return moo; } __set { moo = value; } }

              C Offline
              C Offline
              Chadwick Posey
              wrote on last edited by
              #6

              Code sample: PrintArg(0); PrintArg((int)0); PrintArg((Int16)0); PrintArg((short)0); PrintArg((Int32)0); PrintArg((long)0); PrintArg((Int64)0); PrintArg(1); Corresponding IL: .method public hidebysig static void Main() cil managed { .entrypoint // Code size 85 (0x55) .maxstack 1 IL_0000: nop IL_0001: ldc.i4.0 IL_0002: call void Program::PrintArg(valuetype Foo) IL_0007: nop IL_0008: ldc.i4.0 IL_0009: call void Program::PrintArg(valuetype Foo) IL_000e: nop IL_000f: ldc.i4.0 IL_0010: box [mscorlib]System.Int16 IL_0015: call void Program::PrintArg(object) IL_001a: nop IL_001b: ldc.i4.0 IL_001c: box [mscorlib]System.Int16 IL_0021: call void Program::PrintArg(object) IL_0026: nop IL_0027: ldc.i4.0 IL_0028: call void Program::PrintArg(valuetype Foo) IL_002d: nop IL_002e: ldc.i4.0 IL_002f: conv.i8 IL_0030: box [mscorlib]System.Int64 IL_0035: call void Program::PrintArg(object) IL_003a: nop IL_003b: ldc.i4.0 IL_003c: conv.i8 IL_003d: box [mscorlib]System.Int64 IL_0042: call void Program::PrintArg(object) IL_0047: nop IL_0048: ldc.i4.1 IL_0049: box [mscorlib]System.Int32 IL_004e: call void Program::PrintArg(object) IL_0053: nop IL_0054: ret } // end of method Program::Main Notice the lack of a box operation any time the Int32 0 value is used... consistent with the call to the wrong function void Program::PrintArg(valuetype Foo)... but notice the correct box op for the call with 1!?!? Quirky... I am almost convinced this is a compiler bug. The only work around I can think of is to do the following: using System; enum Foo { Bar, None } class Program { static void PrintArg(object x) { if (x is Foo) { PrintFooArg((Foo)x); return; } Console.WriteLine(x.ToString()); } static void PrintFooArg(Foo x) { Console.WriteLine(x.ToString()); } public static void Main() { PrintArg(0); PrintArg((int)0); PrintArg((Int16)0); PrintArg((short)0); PrintArg((Int32)0); PrintArg((long)0); PrintArg((Int64)0); PrintArg(1); PrintArg(Foo.Bar); } } It prints everything as expected....

              ==========

              1 Reply Last reply
              0
              • J joon vh

                try

                PrintArg(-0);

                and

                Console.WriteLine(0.GetType() == 1.GetType());

                and the resharper making it redundant is _very_ odd to say the least. I use it too. It usually looks up whether your type cast has any purpose for this specific case. f.e. casting 0 into object for the purpose of .GetType'ing makes it redundant, because it also has this option without the cast.


                Visual Studio can't evaluate this, can you? public object moo { __get { return moo; } __set { moo = value; } }

                C Offline
                C Offline
                Chadwick Posey
                wrote on last edited by
                #7

                Submitted to Microsoft as a Compiler Bug -- https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=264570[^]

                ============================= I'm a developer, he's a developer, she's a developer, Wouldn'tcha like to be a developer too?

                C 1 Reply Last reply
                0
                • C Chadwick Posey

                  Submitted to Microsoft as a Compiler Bug -- https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=264570[^]

                  ============================= I'm a developer, he's a developer, she's a developer, Wouldn'tcha like to be a developer too?

                  C Offline
                  C Offline
                  Chadwick Posey
                  wrote on last edited by
                  #8

                  Now I know we're not crazy :) From Microsoft -- Thanks for your feedback. We have reproduced this bug on , and we are sending this bug to the appropriate group within the Visual Studio Product Team for triage and resolution. Thank you, Visual Studio Product Team. Posted by Microsoft on 3/22/2007 at 12:21 AM

                  ============================= I'm a developer, he's a developer, she's a developer, Wouldn'tcha like to be a developer too?

                  J 1 Reply Last reply
                  0
                  • C Chadwick Posey

                    Now I know we're not crazy :) From Microsoft -- Thanks for your feedback. We have reproduced this bug on , and we are sending this bug to the appropriate group within the Visual Studio Product Team for triage and resolution. Thank you, Visual Studio Product Team. Posted by Microsoft on 3/22/2007 at 12:21 AM

                    ============================= I'm a developer, he's a developer, she's a developer, Wouldn'tcha like to be a developer too?

                    J Offline
                    J Offline
                    joon vh
                    wrote on last edited by
                    #9

                    Hmmm. Bart De Smet, C# MVP had this to say:

                    For the C#-compiler, the token 0 is parsed just as a token of course; it depends on the context what the semantic will be. Nevertheless you can often just think of 0 as a int (= System.Int32) constant. For the following discussion, I've used this piece of code: using System; class Program { enum Foo { Bar, None } static void PrintArg(object x) { Console.WriteLine("O {0}", x.ToString()); } static void PrintArg(Foo x) { Console.WriteLine("F {0}", x.ToString()); } public static void Main() { PrintArg(Foo.Bar); PrintArg(Foo.None); PrintArg((Foo)0); PrintArg((Foo)1); PrintArg(0); // Implicit cast to Foo.Bar PrintArg(1); PrintArg((int)0); // Implicit cast to Foo.Bar PrintArg((int)1); PrintArg((Int32)0); // Implicit cast to Foo.Bar PrintArg((Int32)1); PrintArg((Int16)0); PrintArg((Int16)1); PrintArg((Int64)0); PrintArg((Int64)1); PrintArg((object)0); PrintArg((object)1); } } You'll see the following as the output: F Bar F None F Bar F None F Bar O 1 F Bar O 1 F Bar O 1 O 0 O 1 O 0 O 1 O 0 O 1 Let's start with the first pair. Nothing weird in here; just a case of strong typing and a one-on-one match for a method to be called. Essentially, enums are first class citizens when it comes down to object typing. Behind the scenes, an enums is an int however (in the default case). The second pair is the same as above; using an explicit cast from to the enum type. On the method overload resolution side of the story, there's no difference with the case above. On to pair three. In here, something different happens. C# only allows implicit conversion of the decimal-integer-literal 0 to any enum (section 6.1.3 of the C# 2.0 standard); other literals don't have implicit conversions (so you need to do something like in case 2). Therefore, the first invocation will result in a call to the Bar argument method overload, while the second one doesn't. Any type, including value types likes an int, derives from System.Object, so the other overload is called (boxing happens though behind the scenes). Pair four and pair five are the same since int and Int32 are equivalent in C# due to the built-in type mapping. Therefore, (int)0 and (Int32)0 are the same as just 0, resulting in

                    C 1 Reply Last reply
                    0
                    • J joon vh

                      Hmmm. Bart De Smet, C# MVP had this to say:

                      For the C#-compiler, the token 0 is parsed just as a token of course; it depends on the context what the semantic will be. Nevertheless you can often just think of 0 as a int (= System.Int32) constant. For the following discussion, I've used this piece of code: using System; class Program { enum Foo { Bar, None } static void PrintArg(object x) { Console.WriteLine("O {0}", x.ToString()); } static void PrintArg(Foo x) { Console.WriteLine("F {0}", x.ToString()); } public static void Main() { PrintArg(Foo.Bar); PrintArg(Foo.None); PrintArg((Foo)0); PrintArg((Foo)1); PrintArg(0); // Implicit cast to Foo.Bar PrintArg(1); PrintArg((int)0); // Implicit cast to Foo.Bar PrintArg((int)1); PrintArg((Int32)0); // Implicit cast to Foo.Bar PrintArg((Int32)1); PrintArg((Int16)0); PrintArg((Int16)1); PrintArg((Int64)0); PrintArg((Int64)1); PrintArg((object)0); PrintArg((object)1); } } You'll see the following as the output: F Bar F None F Bar F None F Bar O 1 F Bar O 1 F Bar O 1 O 0 O 1 O 0 O 1 O 0 O 1 Let's start with the first pair. Nothing weird in here; just a case of strong typing and a one-on-one match for a method to be called. Essentially, enums are first class citizens when it comes down to object typing. Behind the scenes, an enums is an int however (in the default case). The second pair is the same as above; using an explicit cast from to the enum type. On the method overload resolution side of the story, there's no difference with the case above. On to pair three. In here, something different happens. C# only allows implicit conversion of the decimal-integer-literal 0 to any enum (section 6.1.3 of the C# 2.0 standard); other literals don't have implicit conversions (so you need to do something like in case 2). Therefore, the first invocation will result in a call to the Bar argument method overload, while the second one doesn't. Any type, including value types likes an int, derives from System.Object, so the other overload is called (boxing happens though behind the scenes). Pair four and pair five are the same since int and Int32 are equivalent in C# due to the built-in type mapping. Therefore, (int)0 and (Int32)0 are the same as just 0, resulting in

                      C Offline
                      C Offline
                      Chadwick Posey
                      wrote on last edited by
                      #10

                      Yes, I got the same general response from MS... Section 13.1.3 of the ECMA standard states that the decimal-integer-literal 0 can be implicitly cast to an enum type. It does not, however, provide the same rationale as your MVP friend said. It definitely displays the stated behavior, because if you do int x = 0; then pass x as your parameter, it does the box properly. I kindof see the point in why the standard is the way it is now. I still think that it should at least generate some sort of level 4 warning or something... it is not like all of us have the time (or the brain space) to memorize the ECMA and C# 2.0 standards...especially one as esoteric as this.

                      ============================= I'm a developer, he's a developer, she's a developer, Wouldn'tcha like to be a developer too?

                      J 1 Reply Last reply
                      0
                      • C Chadwick Posey

                        Yes, I got the same general response from MS... Section 13.1.3 of the ECMA standard states that the decimal-integer-literal 0 can be implicitly cast to an enum type. It does not, however, provide the same rationale as your MVP friend said. It definitely displays the stated behavior, because if you do int x = 0; then pass x as your parameter, it does the box properly. I kindof see the point in why the standard is the way it is now. I still think that it should at least generate some sort of level 4 warning or something... it is not like all of us have the time (or the brain space) to memorize the ECMA and C# 2.0 standards...especially one as esoteric as this.

                        ============================= I'm a developer, he's a developer, she's a developer, Wouldn'tcha like to be a developer too?

                        J Offline
                        J Offline
                        joon vh
                        wrote on last edited by
                        #11

                        Chadwick Posey wrote:

                        esoteric

                        Lois Griffin: Peter, it's great they picked your theme, but isn't it a little esoteric?
                        Peter Griffin: Esoteric...?
                        \[Cut-scene: inside Peter's head\]
                        Man 2: Could it mean sexy?
                        Man 3: I think it's a science term.
                        Man 4: Fellas, fellas, esoteric means delicious.
                        \[Back to reality\]
                        Peter Griffin: Lois, Who's the Boss? is not a food.
                        Brian Griffin: Swing and a miss. 
                        

                        I'm sorry, big words usually provoke funny movie or TV quotes, rather than their actual meaning. I'm not a retard, just not native-english-speaking ;)


                        Visual Studio can't evaluate this, can you? public object moo { __get { return moo; } __set { moo = value; } }

                        1 Reply Last reply
                        0
                        Reply
                        • Reply as topic
                        Log in to reply
                        • Oldest to Newest
                        • Newest to Oldest
                        • Most Votes


                        • Login

                        • Don't have an account? Register

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • World
                        • Users
                        • Groups