11 Feb 2008 lupus   » (Master)

The future of C#

C# as a programming language is still young and has evolved nicely in the last few years: most of the new features take it closer to a high-level language, allowing shorter and nicer code for common patterns. A language needs to be able to cover a wide spectrum of usages to be considered mature but there is one side of the spectrum that has been neglected in C# for far too long: the low level side close to IL code.

Someone already hacked up a program that uses a preprocessor and ilasm to inject IL into C# code, but this approach has many drawbacks (too many to list them all here).

Inline IL code should integrate with the rest of the C# program as closely as possible, allowing, for example, to reference labels defined in C# code from branches in IL code or using the names of local variables and arguments for opcodes like ldloc and ldarg.

The proposal here is to allow IL code as a new statement in the form:


  unsafe LITERAL_STRING;
This is similar to the traditional way inline assembly has been done (gcc's __asm__ ("code") statement), it's very unlikely to clash with other possible uses of the unsafe keyword and also conveys the notion that IL code may break type safety, IL language rules etc. It has also the added property that all the code needed to implement this support could be easily copied in a separate library and used in standalone programs to, say, simplify code emission for Reflection.Emit (this inline IL support has been implemented inside the Mono C# compiler, so it's C# code that uses Reflection.Emit as the backend).

So, without further ado, the standard sample program written with inline IL:


class InlineIL {
  static void Main () {
    unsafe @"
     ldstr ""Hello, world!""
     call void class [mscorlib]System.Console::WriteLine(string)
    ";
  }
}
Ok, that kind of code is written more easily in C# proper, so what about things that IL code can do, but that C# code can't? Ever wanted to be able to change the value of a boxed integer? In C# you can't, but this is very easy with inline IL:

static void ChangeInt (object intval, int new_value) {
  unsafe @"
    ldarg.0
    unbox [mscorlib]System.Int32
    ldarg.1
    stind.i4
  ";
}
The following code will print 2:

  object boxed = 1;
  ChangeInt (boxed, 2);
  Console.WriteLine (boxed);
Of course you can access types and fields defined by the C# program currently being compiled, consider the following example:

class InlineIL {
  static int field1;
  static void Main () {
    int localvar = 1;
    unsafe @"
      ldloc localvar
      stsfld int32 class InlineIL::field1
    ";
  }
}
Note that in this case, the compiler won't emit warnings about field1 and localvar being never used and of course you'll get an error if you mispell the field name in IL code as you would in C# code.

The main usage of the new feature would be for some corlib methods in mono or for more easily implementing test cases for the JIT and runtime test suites: some specific IL code patterns (that may not be expressed in C# or that there is no guarantee C# will compile to the effecting code) can be easily written while the rest of the boilerplate code needed by the unit testing program can be written in much more readable C#. That said, this opens many possibilities for a creative hacker, finally free of the constraints of C#.

Happy hacking!

Latest blog entries     Older blog entries

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!