Sunday, November 21, 2010

Constant zero moonlighting as enum. C# enum gotcha

TheLib.cs:

using System;

public static class TheLib
{
 public static void Born()
 {
  Console.WriteLine("Hello World");
 }
 
 public static void Test(object n)
 {
  Console.WriteLine("From Object");
 } 

}

LibUser.cs:

using System;

class Program 
{
 static void Main()
 {
   TheLib.Born();
   TheLib.Test(0);
   TheLib.Test(1);
 }
}

Compile:
mcs /target:library TheLib.cs
mcs /reference:TheLib.dll LibUser.cs
mono LibUser.exe

Output:
Hello World
From Object
From Object

Rewrite TheLib.cs:

using System;

public enum TestEnum { Alpha = 1, Beta = 2 };

public static class TheLib
{
 public static void Born()
 {
  Console.WriteLine("Ni hao, shi jie");
 }
 
 public static void Test(object n)
 {
  Console.WriteLine("From Object");
 } 

 public static void Test(TestEnum e)
 {
  Console.WriteLine("From Enum");
 }
}

Recompile TheLib.cs:

mcs /target:library TheLib.cs

Re-run LibUser.exe:

mono LibUser.exe

Output:
Ni hao, shi jie
From Object
From Object

Though we can see that the recompilation of library is in effect already (the hello world message changed). The zero as an implicit enum (which was decided by the C# language designer) didn't take effect in recompilation of the DLL. Zero moonlighting as an enum is a bad language decision, it just add inconsistency on software component(s).

To see that inconsistency, recompile the main program and re-run it:
mcs /reference:TheLib.dll LibUser.cs
mono LibUser.exe

Output:
Ni hao, shi jie
From Enum
From Object

You can see that zero now maps to enum when it was recompiled. Exactly same code, yet different behavior depending on recompilation of consuming code.

0 like its other constant brothers(1, -5, 6, 8, etc) should be treated equally, i.e. zero should be an integer type at all circumstances.

If an enum zero is desired, put at sign(@) to good use, if '@' sign was used as a verbatim literal, and string literal, why not use it as contextual literal? i.e. @0 is treated as a zero enum. I hope they can fix this enum gotcha in C# 5, if not, at least on C# 6, C# 7


using System;

class Program 
{
 static void Main()
 {
   TheLib.Born();   
   TheLib.Test(1);
   TheLib.Test(0); // must be still an integer even there's an enum overload function. unfortunately, it's not
   TheLib.Test(@0); // this shall be an enum if C# team would heed my suggestion ;-)
 }
}

No comments:

Post a Comment