Exploring System.Void Part II

clock Saturday, 30 April 2011 18:22 by sunny

In my previous post, I described the role of System.Void in the .NET framework and demonstrated some of the restrictions placed on the type.
In this post, I’ll postulate why those restrictions are in place and I’ll try to bypass them in an attempt to create an instance of the type.

The restrictions on the System.Void type are documented in the Common Language Infrastructure (CLI) specification (ECMA-335)PDF Document.
I find two of these restrictions particularly interesting:

“The type System.Void is never boxable.” (Section 8.2.4)
“No location or value shall have System.Void” (Section 8.7)

Why is instantiation of the System.Void type forbidden? After all, as long as methods are not allowed to declare a return type of System.Void, the purpose of the type as discussed in my previous post remains intact, regardless of whether instances are allowed to exist or not.

So, what’s the harm in permitting instances of this type to exist? I proffer the following explanations.

Firstly, from a philosophical standpoint, it doesn’t make much sense to have the ability to instantiate a type that methods cannot declare as a return type, because that is effectively saying that you can create this object but your methods cannot pass its value (unless in a boxed representation or masqueraded as an inherited type) around.

Secondly, some unexpected issues can arise when calling methods declared in generic types. For example, if developers can instantiate System.Void, they’ll expect to be able to compile and run the following code, but by so doing produce a method that has a System.Void return type.

class Program
{
	static void Main(string[] args)
	{
		var instance = new MyClass<System.Void>().GetInstance();			
	}
	
}

class MyClass<T> where T:new()
{
	public T GetInstance()
	{
		return new T();
	}
}

The compiler/runtime can be updated to prevent such code from compiling or running, however it’s cleaner to have a rule that states that System.Void cannot be instantiated and that the expression “System.Void” is illegal anywhere in C#.

The last explanation I proffer has to do with pointers in C#, and I think it is the most functional explanation.
You can get the System.Type object of a value type pointer with the following expression:

typeof(MyStruct*)
For example:
typeof(int*)
evaluates to a System.Type object called System.Int32*

Similarly, typeof(bool*), typeof(DateTime*), typeof(char*) and typeof(System.Guid*) will evaluate to System.Type objects called System.Boolean*, System.DateTime*, System.Char* and System.Guid* respectively.

Now, there is a special kind of pointer called the void pointer which can point to any pointer type.
The type declaration for a void pointer is void*, and the following expression gets the System.Type object of a void pointer:

typeof(void*)
It evaluates to a System.Type object called System.Void*

You can already see how an ambiguity is introduced if instances of System.Void were allowed to exist.
In that scenario, typeof(System.Void*) would evaluate to a System.Type object also called System.Void*.
It would be impossible (or at least error-prone) to tell if the object is for a pointer to System.Void or for the special void pointer.

Nevertheless, and in spite of my failed attempts to instantiate System.Void in the previous post, it is possible to create an instance of System.Void -- by making it a static field.

// Metadata version: v2.0.50727
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
  .ver 2:0:0:0
}
.assembly ConsoleApplication1
{
  .hash algorithm 0x00008004
  .ver 1:0:0:0
}
.module ConsoleApplication1.exe
// MVID: {60F1E74C-3123-4EF0-8269-A0C3B8B85ADF}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       // WINDOWS_CUI
.corflags 0x00000001    //  ILONLY
// Image base: 0x00670000


// =============== CLASS MEMBERS DECLARATION ===================

.class private auto ansi beforefieldinit Program
       extends [mscorlib]System.Object
{
  .field public static valuetype [mscorlib]System.Void o
  .method private hidebysig static void  Main() cil managed
  {
    .entrypoint
    // Code size       1 (0x1)
    .maxstack  8
    IL_0000:  ret
  } // end of method Program::Main

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // Code size       7 (0x7)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  ret
  } // end of method Program::.ctor

} // end of class Program

The IL code listing above is equivalent to the following C# program (if it were possible to compile)

class Program
{
	public static System.Void o;
	static void Main()
	{
	}
}

If I compile the IL code using ilasm and run it, I don’t observe any errors, unlike in my previous attempts.
What does this mean? Did it create an instance of the type? Is the runtime skipping over that System.Void field creation instruction? Is the program dying silently?

This is a good example of the "If a tree falls in a forest and no one is around to hear it, does it make a sound?" philosophical riddle.

What I need is some observability. I need to be absolutely sure that the type was instantiated (or not).

I’ll just modify the code a little bit to get some output:

class Program
{
	public static System.Void o;
	static void Main()
	{
		Console.WriteLine(o.ToString());

	}
}

which translates to the following IL code:

// Metadata version: v2.0.50727
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
  .ver 2:0:0:0
}
.assembly ConsoleApplication1
{
  .hash algorithm 0x00008004
  .ver 1:0:0:0
}
.module ConsoleApplication1.exe
// MVID: {EE60F7FD-BD3D-46C8-B353-A459F5119496}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       // WINDOWS_CUI
.corflags 0x00000001    //  ILONLY
// Image base: 0x00260000


// =============== CLASS MEMBERS DECLARATION ===================

.class private auto ansi beforefieldinit Program
       extends [mscorlib]System.Object
{
  .field public static valuetype [mscorlib]System.Void o
  .method private hidebysig static void  Main() cil managed
  {
    .entrypoint
    // Code size       22 (0x16)
    .maxstack  8
    IL_0000:  ldsflda    valuetype [mscorlib]System.Void Program::o
    IL_0005:  constrained. [mscorlib]System.Void
    IL_000b:  callvirt   instance string [mscorlib]System.Object::ToString()
    IL_0010:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_0015:  ret
  } // end of method Program::Main

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // Code size       7 (0x7)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  ret
  } // end of method Program::.ctor

} // end of class Program

If I run the program, I get a fatal InvalidProgramException error message. The issue is that ToString() is defined on the base System.Object class. When I call System.Void.ToString(), the runtime boxes the value type to an object before calling the ToString() method.
Remember that rule which states that System.Void cannot be boxed. It is enforced by the runtime. There is a check that the value is not System.Void during boxing, and if the check fails, the program is halted.

On a side note, this is another good reason to avoid boxing whenever possible. There is some overhead, besides copying the value to the boxed representation, due to many type checks.

System.Void does not define any members that we can access. The other members (GetType(), ToString(), GetHashCode(), etc.) are all inherited. Calling the inherited methods will lead to boxing which is prohibited. How can we observe its existence?

There’s one way.

// Metadata version: v2.0.50727
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
  .ver 2:0:0:0
}
.assembly MultiVoid
{
  .permissionset reqmin
             = {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
  .hash algorithm 0x00008004
  .ver 1:0:0:0
}
.module MultiVoid.exe
// MVID: {AC411515-B789-4594-B52B-1EC2668D16C9}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) 
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       // WINDOWS_CUI
.corflags 0x00000001    //  ILONLY
// Image base: 0x00BC0000


// =============== CLASS MEMBERS DECLARATION ===================

.class private auto ansi beforefieldinit Program
       extends [mscorlib]System.Object
{
  .field public static valuetype [mscorlib]System.Void o
  .field public static valuetype [mscorlib]System.Void p
  .method private hidebysig static void  Main() cil managed
  {
    .entrypoint
    // Code size       35 (0x23)
    .maxstack  1
    .locals init (valuetype [mscorlib]System.Void& pinned V_0,
             valuetype [mscorlib]System.Void& pinned V_1)
    IL_0000:  ldsflda    valuetype [mscorlib]System.Void Program::o
    IL_0005:  stloc.0
    IL_0006:  ldloc.0
    IL_0007:  conv.i
    IL_0008:  conv.i4
    IL_0009:  call       void [mscorlib]System.Console::WriteLine(int32)
    IL_000e:  ldc.i4.0
    IL_000f:  conv.u
    IL_0010:  stloc.0
    IL_0011:  ldsflda    valuetype [mscorlib]System.Void Program::p
    IL_0016:  stloc.1
    IL_0017:  ldloc.1
    IL_0018:  conv.i
    IL_0019:  conv.i4
    IL_001a:  call       void [mscorlib]System.Console::WriteLine(int32)
    IL_001f:  ldc.i4.0
    IL_0020:  conv.u
    IL_0021:  stloc.1
    IL_0022:  ret
  } // end of method Program::Main

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // Code size       7 (0x7)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  ret
  } // end of method Program::.ctor

} // end of class Program

The IL code above translates to the following uncompilable C# code:

class Program
{
	public static System.Void o;
	public static System.Void p;
	static void Main()
	{
		unsafe
		{

			fixed (System.Void* i = &o)
			{
				Console.WriteLine((int)i);
			}

			fixed (System.Void* j = &p)
			{
				Console.WriteLine((int)j);
			}

		}

	}
}

It displays the addresses of the System.Void instances in memory: If you run the IL code, you’ll see an output with the memory addresses of the two instances like as shown below:

Congratulations! You just created two instances of the forbidden System.Void type!

That may be as far as you may go. The runtime will detect attempts to place the instance on the evaluation stack, which is necessary to return the instance value from a method.

Digg It!RedditDel.icio.usStumbleUponTechnorati
Tags:   , , ,
Categories:   .NET | C#
Actions:   E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

Exploring System.Void Part I

clock Friday, 31 December 2010 17:03 by sunny

When calling a method in a dynamically created instance of a type that is discovered at runtime, it's useful to discover the types of the method parameters and the method return type. This information is needed to successfully call the method and retrieve its return value.

It's also useful to discover if the method doesn't have a return type, so that we know not to expect a return value.
One way to find out is to check if the MethodBase.Invoke call returns a null, since a dynamically invoked method that has no return type will return a null. However, this is not the best approach for the following reasons.

Firstly, any method that returns a reference type can return a null, rendering such null checks unreliable.

Secondly, this approach cannot be used to determine the return type before invoking the method.

Fortunately, MethodInfo objects have a ReturnType property that developers can inspect to determine the return type before invoking the method. For instance, if the method returns a string type, MethodInfo.ReturnType will evaluate to typeof(string). It would seem that the natural way to determine if a method does not define a return type would be to check if MethodInfo.ReturnType == typeof(null), however, that won't work because the expression typeof(null) is illegal in C#. Null is not a type.

What's needed is a specially marked type that can be used in the typeof() evaluation to determine that the method does not have a return type. Think about that for a few seconds to get a feel of how counter-intuitive that sounds.
The issue with this approach is that if a method returns an instance of the proposed special type, then the test becomes inconclusive and unreliable. To prevent this from happening, the runtime must bar creation of methods that return this special type.

Enter the System.Void structure. This type is specially designated by .NET for just this purpose. In C#, the void keyword is an alias for the System.Void structure, thus MethodInfo.ReturnType == typeof(void) is a reliable means of discovering if a method has a return type. As expected, no method is allowed to define System.Void as its return type.

This solution looks good and seems like a perfect answer to the "no return type detection" problem. However, there may be a lot more involved. C# and the CLR strangely takes it one step further by disallowing instantiation of the System.Void type by any means. Allow me to demonstrate:

Attempt 1: Try to instantiate System.Void normally

static void Main()
{
    object o = new System.Void();
    //object o = new void() is illegal in C# lingo
}
You'll get a "System.Void cannot be used from C# -- use typeof(void) to get the void type object" (CS0673) error message if you try to compile the code.

Attempt 2: Try to instantiate System.Void dynamically

static void Main(string[] args)
{

    object o = Activator.CreateInstance(typeof(void));
            
}	
It compiles, but when you try to run it, you get a "Cannot dynamically create an instance of System.Void." error message.

Attempt 3: Bypass the C# compiler, Try to create it directly from IL

// Metadata version: v2.0.50727
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )
  .ver 2:0:0:0
}
.assembly ConsoleApplication1
{

  .hash algorithm 0x00008004
  .ver 1:0:0:0
}
.module ConsoleApplication1.exe
// MVID: {47CAF74F-C24A-400E-A0F9-26EB27500120}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       // WINDOWS_CUI
.corflags 0x00000001    //  ILONLY
// Image base: 0x00D10000


// =============== CLASS MEMBERS DECLARATION ===================

.class private auto ansi beforefieldinit Program
       extends [mscorlib]System.Object
{
  .field public static valuetype [mscorlib]System.Void o
  .method private hidebysig static void  Main() cil managed
  {
    .entrypoint
    // Code size       12 (0xc)
    .maxstack  8
    IL_0000:  ldsflda    valuetype [mscorlib]System.Void Program::o
    IL_0005:  initobj    [mscorlib]System.Void
    IL_000b:  ret
  } // end of method Program::Main

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // Code size       7 (0x7)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  ret
  } // end of method Program::.ctor

} // end of class Program

The IL code above is equivalent to the following C# code
using System;

class Program
{
	public static System.Void o;
	static void Main()
	{
		o = new System.Void();
	}
}
If you compile the IL code with ilasm, It compiles successfully, however it fails verification when you run Peverify against the compiled assembly. If you try to run the assembly, it runs into a fatal InvalidProgramException exception.
If you replace occurrences of System.Void in the IL code to any other struct in the System namespace (besides the ones that map to simple types -- they have a different syntax in IL), the IL code will compile and run smoothly.

From the examples shown above, we have established that the C# compiler and runtime prevents instantiation of the System.Void type. In my next post, We'll explore the System.Void type some more and try to figure out why the runtime doesn't want it to exist.

Happy new year!!

Digg It!RedditDel.icio.usStumbleUponTechnorati
Tags:   , , ,
Categories:   .NET | C#
Actions:   E-mail | Permalink | Comments (0) | Comment RSSRSS comment feed

I Want a Native C# Compiler

clock Monday, 26 January 2009 11:39 by sunny

Wouldn’t it be nice if C# code could be compiled directly to machine code? Having such a compiler would position C# as a serious system programming language.
Developers would be able to write system software for routers, for instance, in C#.

I don’t see any reason why such a compiler should not exist. In fact, the creation of a native C# compiler will be well justified.

C# is a well designed programming language. It would be a shame if the language is stuck forever with the .NET/Mono frameworks, especially if you consider that there is no reason why the language has to be inextricable tied to these frameworks.
There is no requirement that C# code must compile to IL and there are no language-level assumptions that the compiled code has to be machine-independent.
High-level features routinely used by developers such as threading and reflection, are .NET library calls and have no connection to the language itself. The only high-level feature that the language implies is a garbage collection system. In fact there are language-level hints that C# can be a system-level programming language -- how often do you use the volatile, stackalloc and fixed keywords?

The C# developer base is huge, so a native C# compiler will push the language even further to new platforms and projects that are currently unsuitable for development with C#. It will enable developers to write ALL their code; high-level and low-level in C#. Higher-level code will be compiled to IL, whereas lower-level code will be compiled to machine code.

A native C# compiler would be great for coding libraries, for instance, a proprietary encryption or compression algorithm. With a native C# compiler, an algorithm can be coded in C# and compiled as a native code library. This library can be linked to and used in systems without any .NET (or alternative) frameworks.
The best part is that if this library is needed for a .NET/Mono project -- all that is needed is recompilation and the algorithm will scale to managed code without having to port the library or use unmanaged calls. It will work great in both managed and unmanaged worlds.

The language is an open standard, so anyone with the time, expertise and resources can create a native C# compiler. Also, to be successful, this compiler only needs to support C# version 2.0.
Language features introduced in versions 3.0 and 4.0 are not that important and can be considered “Microsoft extensions” to the C# language. Indeed, Anders Hejlsberg admitted that features added in C# 2.0 were features they didn’t have time or didn’t know how to properly implement in C# 1.0.

If you are still not convinced about the viability of such a compiler, take a look at the compilers available for the D language. They are living proof that such a compiler is feasible and will compile a modern language directly to machine code, complete with a (small) runtime, memory management and type system.

 

Digg It!RedditDel.icio.usStumbleUponTechnorati
Tags:   ,
Categories:   C# | Random Thoughts
Actions:   E-mail | Permalink | Comments (6) | Comment RSSRSS comment feed

C# Brainteasers Part I

clock Sunday, 26 October 2008 20:40 by sunny

Every now and then, I pick up C# Precisely by Peter Sestoft and Henrik I. Hansen, a great C# reference book that should be recommended more often.
Every time I read the text, I find bemusingly odd but very correct C# code examples.

Here are some C# brainteasers I've compiled from the book. The answers are at the end of this post.

1. What does the following code display?

class Concat
{
    static void Main()
    {
        Console.WriteLine(20 + 45 + "A");
        Console.WriteLine("A" + 20 + 45);
    }
}

Okay, that one was easy -- how about the rest?

2. What is wrong with this code?

class One
{
    sealed void SealedOnly()
    {
        // Do something
    }
    
    virtual void Virt()
    {
        // Do something
    }
}

3. What is wrong with this code?

class BaseClass
{
    public BaseClass (string Arg0)
    {
        //Do stuff       
    }
}

class DerivedClass : BaseClass 
{
    //Do more stuff
}

4. What is wrong with this code?


class Student
{
    public Student (string Name) 
    {
        //Call other constructor
        this.Student(Name, null);
    }

    public Student (string Name, DateTime? DateEnrolled)
    {
        this.name = Name;
        this.dateEnrolled = DateEnrolled;       
    }

    private string name;
    private DateTime? dateEnrolled;

}

5. What is the class access modifier for class A? how about class B?

class A
{
    class B
    {

    }
}


Answers:

1.
The code will display:

65A
A2045

This is because the + operator is left associative.


2.
The code will not compile because of errors (shown in comments) below.

class One
{
    sealed void SealedOnly() //error CS0238: Cannot be sealed because it is not an override 
    {
         // Do something
    }

    virtual void Virt() //error CS0621: virtual or abstract members cannot be private
    {
       // Do something
    }
}

You can’t have a sealed method that does not override a base method.
You can’t have a virtual or abstract method with a private access modifier.


3.
The code will not compile because of the error (shown in the comment) below.
class BaseClass
{
    public BaseClass (string Arg0)
    {
        //Do stuff       
    }
}

class DerivedClass : BaseClass // error CS1501: No overload for method 'BaseClass' takes '0' arguments (DerivedClass must explicitly call BaseClass constructor because there is no parameterless base constructor)
{
    //Do more stuff
}
This one is a bit tricky to explain. The C# compiler generates a parameterless constructor for concrete classes without any defined constructors. If there was no constructor defined for the base class, then the C# compiler will generate a parameterless constructor.
A parameterless constructor will also be generated for the derived class (since it doesn’t have any constructors) which will override the parameterless constructor for the base class.

In this case, a constructor with a single parameter was defined for the base class, so the C# compiler will NOT generate a parameterless constructor for the base class. The derived class however will have a parameterless constructor generated. The problem with the code snippet above is that the derived class’s parameterless constructor can not find a base parameterless constructor to override.

To resolve this issue, you can add a parameterless constructor to the base class, add a constructor with the same signature as the one in the base class to the derived class, or add a parameterless constructor to the the derived class with this declaration:
public DerivedClass(): base("")
{
}
This creates a parameterless constructor for the derived class which calls the base class constructor


4.
The code will not compile because of the error (shown in the comment) below.
    class Student
    {
        public Student(string Name) 
        {
            this.Student(Name, null); // error CS0117: 'Student' does not contain a definition for 'Student'
        }

        public Student(string Name, DateTime? DateEnrolled)
        {
            this.name = Name;
            this.dateEnrolled = DateEnrolled;
        }

        private string name;
        private DateTime? dateEnrolled;

    }
You cannot call constructor code using regular method access syntax, even from another constructor.
To call another constructor, use this syntax:
public Student(string Name) : this(Name, null)
{
}

5.
 A - internal
 B - private
Top-level classes without a class access modifier default to internal (and can only be either public or internal).
Nested classes without a class access modifier default to private.


Digg It!RedditDel.icio.usStumbleUponTechnorati
Tags:  
Categories:   C#
Actions:   E-mail | Permalink | Comments (1) | Comment RSSRSS comment feed