[M3devel] An awkward interaction of language properties

Rodney M. Bates rodney_bates at lcwb.coop
Fri Feb 17 21:46:53 CET 2012


So, I have the following mutually recursive types:
----------------------------------------------------------------------------
DataStruct.i3:
INTERFACE DataStruct
; TYPE T = RECORD
              Relatives : ListRef
            (* Other fields. *)
            END
; TYPE ListRef = REF List
; TYPE List = ARRAY OF T
; END DataStruct
.
----------------------------------------------------------------------------

This works fine in Modula-3, if all three types are declared in the same scope.

Now suppose instead of builtin type constructor ARRAY OF, I need my set of
relatives to be an instantiation of a complex container data structure,
with a generic parameter for the type of its elements:

----------------------------------------------------------------------------
Container.ig:
GENERIC INTERFACE Container ( Elem )
(* Where Elem exports Elem.T, a type other than an open array type. *)
; TYPE T <: ROOT (* A container of Elem.T. *)
; PROCEDURE Get ( C : T ; Selector : INTEGER ; VAR Element : Elem . T )
; END Container
.
----------------------------------------------------------------------------
INTERFACE DTContainer = Container(DataStruct2) END DTContainer .
----------------------------------------------------------------------------
DataStruct2.i3:
INTERFACE DataStruct2
; IMPORT DTContainer
; TYPE Node = RECORD
                 Relatives : DTContainer . T
               (* Other fields. *)
               END
; END DataStruct2
.
----------------------------------------------------------------------------

This has cyclic imports and won't compile.  (A generic actual interface is
implicitly an import, which is made explicit by the rewrite rule for an
instantiation, 2.5.5)

The rule that recursive types have to be in the same scope and the fact that
an instantiation is a separate interface are irreconcilable.

The only way I can think of is to make the Relatives field be a REFANY,
and not import DTContainer into DataStruct2.  This loses static safety,
but at least it will be replaced by dynamic safety, at the cost of
runtime narrow checks every time I use Relatives.

Of course, I can cut down some on the frequency of RT type checks by grouping
nearby accesses to a Relatives field with a TYPECASE or assignment to a
variable (declared inside a module) of type DTContainer.T.

Anybody have any other thoughts on how to handle this?






More information about the M3devel mailing list