Cook Computing

Component Pascal

May 30, 2002 Written by Charles Cook

Component Pascal, described in the interesting Compiling for the .NET Common Language Runtime, does support covariant return types.

I verified this in my first (and last?) CP program:


MODULE HELLO;
IMPORT CPmain, Console;
  
TYPE 
  BaseParser = EXTENSIBLE RECORD END;
  FaultParser = EXTENSIBLE RECORD (BaseParser) END;
  
  BaseRet = EXTENSIBLE RECORD END;
  BaseRetPtr = POINTER TO BaseRet;
	
  FaultRet = RECORD (BaseRet) END;
  FaultRetPtr = POINTER TO FaultRet;
 
VAR
  bp : POINTER TO BaseParser;
  bret : BaseRetPtr;
  fp : POINTER TO FaultParser;
  fret : FaultRetPtr;

PROCEDURE (IN p : BaseParser) Foo() :  BaseRetPtr, NEW , EXTENSIBLE;
VAR tmp : BaseRetPtr;
BEGIN
  NEW(tmp);
  RETURN tmp;
END Foo;

PROCEDURE (IN p : FaultParser) Foo() :  FaultRetPtr;
VAR tmp : FaultRetPtr;
BEGIN
  NEW(tmp);
  RETURN tmp;
END Foo;
  
BEGIN
  NEW(bp);
  bret := bp.Foo();
  NEW(fp);
  fret := fp.Foo();
END HELLO.

Method Foo in FaultParser overrides Foo in the base class and returns a pointer to FaultRet instead of BaseRet. CP handles the covariant return type via a two-pronged approach. First, Foo in the derived class, although defined in the IL method signature to return a type of BaseRet, actually returns a type of FaultRet:


.method assembly final virtual instance class HELLO.BaseRet 
        Foo() cil managed
{
  // Code size       8 (0x8)
  .maxstack  8
  .locals init ([0] class HELLO.FaultRet tmp)
  IL_0000:  newobj     instance void HELLO.FaultRet::.ctor()
  IL_0005:  stloc.0
  IL_0006:  ldloc.0
  IL_0007:  ret
} // end of method FaultParser::Foo

Second, the compiler recognizes that a covariant return is required and automatically downcasts the returned BaseRet to the required FaultRet type:


IL_0015: call       instance class HELLO.BaseRet HELLO.FaultParser::Foo()
IL_001a: castclass  class HELLO.FaultRet
IL_001f: stsfld     class HELLO.FaultRet HELLO.HELLO::fret

I don't how the compiler recognizes that a method supports covariant return when referencing another CP assembly because there doesn't seem to be any metadata to indicate this (even when all the types are marked as exportable)