Component Pascal
Thursday 30 May 2002
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)