Mobile Software Engineering

2007-11-26 by tamberg

Implementing Oberon Modules in C#

The C# language unfortunately does not provide a module feature. Nevertheless, the access modifier internal makes implementing Oberon-style module semantics quite straightforward. On the binary level an Oberon module comes very close to a .NET assembly. In code, the C# modifier internal limits member accessibility to a single assembly, so we can use it to designate module wide visibility.

Module members that are marked as exported in Oberon become public in C#. Further, for better readability the MODULE keyword can be emulated with a C# namespace keyword - as long as every assembly is assigned one unique namespace. To import another module, reference its assembly and insert a using statement for the corresponding namespace.

Here's an example of a module M in Component Pascal. Note that comments are also in Component Pascal syntax. All procedure and method bodies are empty for the sake of brevity.

(* M.odc *)

MODULE M;

  IMPORT Q; (* imported module *)

  TYPE
    T* = POINTER TO RECORD END; (* exported class *)
    U = POINTER TO RECORD END;

  VAR
    i*: INTEGER; (* exported module variable *)
    j: INTEGER;

  PROCEDURE (t: T) A*, NEW; BEGIN END A; (* exported method *)
  PROCEDURE (t: T) B, NEW; BEGIN END B;

  PROCEDURE F* BEGIN END F; (* exported procedure *)
  PROCEDURE G BEGIN END G;

BEGIN
  (* module initialization ... *)
END M.

The same module could be implemented in C# as follows

// M.cs

namespace M {

  using Q; // imported module

  public sealed class T { // exported class
    public void A () {} // exported method
    internal void B () {}
  }
  
  sealed class U {} // internal by default

  public sealed class M {
    M () {} // private by default
    public static int i; // exported module variable
    internal static int j;
    public static void F () {} // exported procedure
    internal static void G () {}
    static M () {
      // module initialization ...
    }
  }

}

Now look at the interface definition generated out of the compiled Component Pascal module

DEFINITION M;

  TYPE
    T = POINTER TO RECORD 
      (t: T) A, NEW
    END;

  VAR
    i: INTEGER;

  PROCEDURE F;

END M.

And the public interface of the compiled C# code as generated by Lutz Röder's Reflector

namespace M {

  public sealed class T {
    public T();
    public void A();
  }

  public sealed class M {
    public static int i;
    public static void F();
  }

}

To sum things up: Implementing modules is possible and quite easy thanks to Anders Hejlsberg who - familiar with units, Delphi's module feature - presumably sneaked the internal modifier into C#.