[comp.lang.modula2] definition module loops

bowen@cs.Buffalo.EDU (Devon E Bowen) (05/10/91)

What are the rules regarding circular imports? For example, the following
code must be invalid because 'a' is never declared.

DEFINITION MODULE file1;
FROM file2 IMPORT a;
END file1.

DEFINITION MODULE file2;
FROM file1 IMPORT a;
END file2.

Yet it seems like the following should be valid because there is no such
conflict.

DEFINITION MODULE file1;
FROM file2 IMPORT b;
VAR a : INTEGER;
END file1.

DEFINITION MODULE file2;
FROM file1 IMPORT a;
VAR b : INTEGER;
END file2.

I haven't been able to find anywhere in Wirth's 4th edition that addresses
this issue. So what are the formal rules in this situation and what techniques
do most Modula-2 compilers use to implement them?

Devon

gmurray@ibmpcug.co.uk (G Murray) (05/12/91)

In article <75730@eerie.acsu.Buffalo.EDU> bowen@cs.Buffalo.EDU (Devon E Bowen) writes:
> 
> What are the rules regarding circular imports? For example, the following
 
 Stony Brook explicitly states that circular imports are not allowed.
The general rule that they apply is that the order of compilation is such
that the definition modules for all modules are imported *must* be compiled
before the module that imports them.

 I would think that most, if not all, compilers imposed similar restrictions
on circular imports. 


----------------------------------------------------------------------
Graham Murray			  Email gmurray@ibmpcug.co.uk
Senior Programmer		    OR  gmurray@cix.compulink.co.uk
Gravatom Technology Ltd		  Voice +44 329 823986
----------------------------------------------------------------------

-- 
Automatic Disclaimer:
The views expressed above are those of the author alone and may not
represent the views of the IBM PC User Group.
-- 

bowen@cs.Buffalo.EDU (Devon E Bowen) (05/13/91)

In article <1991May12.071720.29928@ibmpcug.co.uk>, gmurray@ibmpcug.co.uk (G Murray) writes:
|>  Stony Brook explicitly states that circular imports are not allowed.

Sounds good to me (a lot easier to implement). But at the end of section
14 of the Report on The Programming Language Modula-2 in Wirth's book, he
says

	If circular references occur among modules, their order of
	initialization is not defined.

Which implies this circular nature does exist. Well, I guess I'll just
leave this feature out until there is a definte need shown for it.

Thanks for the help.

Devon

eepjm@cc.newcastle.edu.au (05/13/91)

In article <76170@eerie.acsu.Buffalo.EDU>, bowen@cs.Buffalo.EDU
      (Devon E Bowen) writes:
> 
> In article <1991May12.071720.29928@ibmpcug.co.uk>, gmurray@ibmpcug.co.uk (G Murray) writes:
> |>  Stony Brook explicitly states that circular imports are not allowed.
> 
> Sounds good to me (a lot easier to implement). But at the end of section
> 14 of the Report on The Programming Language Modula-2 in Wirth's book, he
> says
> 
> 	If circular references occur among modules, their order of
> 	initialization is not defined.
> 
> Which implies this circular nature does exist. Well, I guess I'll just

There are two separate issues here.  To determine the order of initialisation,
you need to look at the definition modules AND the implementation modules.
The original question was about definition modules only.  My impression is
that the difficult sort of circularity (involving definition modules) is
always illegal, and the other sort is legal.

Peter Moylan            eepjm@cc.newcastle.edu.au

protonen@daimi.aau.dk (Lars J|dal) (05/13/91)

bowen@cs.Buffalo.EDU (Devon E Bowen) writes:


>In article <1991May12.071720.29928@ibmpcug.co.uk>, gmurray@ibmpcug.co.uk (G Murray) writes:
>|>  Stony Brook explicitly states that circular imports are not allowed.

>Sounds good to me (a lot easier to implement). But at the end of section
>14 of the Report on The Programming Language Modula-2 in Wirth's book, he
>says

>	If circular references occur among modules, their order of
>	initialization is not defined.
...

As far as I know, this corresponds to the implementation modules, not
the definition modules. That is, suppose you have the following modules:

DEFINITION MODULE m1;
VAR x:CARDINAL;
END m1.

DEFINITION MODULE m2;
VAR y:CARDINAL;
END m2.

IMPLEMENTATION MODULE m1;
FROM m2 IMPORT y;
VAR x:CARDINAL;
BEGIN
   x:=1;
   y:=1;
END m1.

IMPLEMENTATION MODULE m2
FROM m1 IMPORT x;
VAR y:CARDINAL;
BEGIN
   x:=2;
   y:=2;
END m2.

If they are compiled in the above order the definition modules will not
use anything undefined. The implementation modules know the type of the
foreign variable (x or y), so there is no problem either. But it is
undefined whether the body of m1 or m2 is executed first, so if one
compiler ends up with x=1 and y=1, you have no guarantee another compiler
will do the same.
(Only Wirth know if that was what he meant so please correct me if I'm
wrong :-) )

Good luck with the implementation!

+--------------------------------------------------------------------------+
|      Lars J|dal       |       (put your favourite quotation here)        |
| protonen@daimi.aau.dk |                                                  |
|--------------------------------------------------------------------------|
| Computer Science Department  -  Aarhus University  -  Aarhus  -  Denmark |
+--------------------------------------------------------------------------+

protonen@daimi.aau.dk (Lars J|dal) (05/13/91)

I forgot to define a main program to use the modules. The modules should be

DEFINITION MODULE m1;
VAR x:CARDINAL;
END m1.

DEFINITION MODULE m2;
VAR y:CARDINAL;
END m2.

IMPLEMENTATION MODULE m1;
FROM m2 IMPORT y;
VAR x:CARDINAL;
BEGIN
   x:=1;
   y:=1;
END m1.

IMPLEMENTATION MODULE m2
FROM m1 IMPORT x;
VAR y:CARDINAL;
BEGIN
   x:=2;
   y:=2;
END m2.

MODULE main_program;
FROM m1 IMPORT x;
FROM m2 IMPORT y;
FROM InOut IMPORT WriteCard;
BEGIN
   WriteCard(x,0);
   WriteCard(y,0);
END main_program.

>If they are compiled in the above order the definition modules will not
>use anything undefined. The implementation modules know the type of the
>foreign variable (x or y), so there is no problem either. But it is
>undefined whether the body of m1 or m2 is executed first, so if one
>compiler ends up with x=1 and y=1, you have no guarantee another compiler
>will do the same.
So the output should be 11 or 22, but the one is as correct as the other.
>(Only Wirth know if that was what he meant so please correct me if I'm
>wrong :-) )

>Good luck with the implementation!

+--------------------------------------------------------------------------+
|      Lars J|dal       |       (put your favourite quotation here)        |
| protonen@daimi.aau.dk |                                                  |
|--------------------------------------------------------------------------|
| Computer Science Department  -  Aarhus University  -  Aarhus  -  Denmark |
+--------------------------------------------------------------------------+

schoebel@bs3.informatik.uni-stuttgart.de (Thomas Schoebel) (05/13/91)

In article <76170@eerie.acsu.Buffalo.EDU> bowen@cs.Buffalo.EDU (Devon E Bowen) writes:
>Sounds good to me (a lot easier to implement). But at the end of section
>14 of the Report on The Programming Language Modula-2 in Wirth's book, he
>says
>
>	If circular references occur among modules, their order of
>	initialization is not defined.
>
>Which implies this circular nature does exist. Well, I guess I'll just
>leave this feature out until there is a definte need shown for it.

Perhaps the distiction between definiton and implementation modules
will make it more clear: In most current compilers, circular imports
amoung definition modules are disallowed (even if the imported objects
would not cause a cycle by their real definition); however, cycles
amoung implementation modulues are possible.

If you divide the definition and implementation parts logically into
different modules, you may view the dependency graph in such a way
that all sorts of modules are always importing from definition modules.
Then there is never an import from an implementation module, so there is
logically never a cycle.
However, the initialization order amoung the modules in the cycle
is undefined; this is the only problem I can see.

As my opinion, in larger systems cycles amoung implementation modules
are nearly unavoidable, but I cannot prove this. It is just an experience
from practice. Theoretically, you can always break down any well-defined
structure into smaller and smaller submodules, so there would be no need
to allow circular imports.

--Thomas

gkt@iitmax.iit.edu (George Thiruvathukal) (05/14/91)

In article <76170@eerie.acsu.Buffalo.EDU>, bowen@cs.Buffalo.EDU (Devon E Bowen) writes:
> 
> In article <1991May12.071720.29928@ibmpcug.co.uk>
> gmurray@ibmpcug.co.uk (G Murray) writes:
> 	If circular references occur among modules, their order of
> 	initialization is not defined.
> 
> Which implies this circular nature does exist.

I would take Dr. Wirth's comment to mean that circular references cannot be
depended upon as a language feature in any given implementation of Modula-2.
It is just too bad that we language implementators have to deal with such
ambiguity in language definitions, especially since it is not a complicated
issue to define.  Circular imports should be outlawed.
-- 
George Thiruvathukal

Laboratory for Parallel Computing and Languages
Illinois Institute of Technology
Chicago

reid@CTC.CONTEL.COM (Tom Reid x4505) (05/17/91)

= I would take Dr. Wirth's comment to mean that circular references cannot be
= depended upon as a language feature in any given implementation of Modula-2.
= It is just too bad that we language implementators have to deal with such
= ambiguity in language definitions, especially since it is not a complicated
= issue to define.  Circular imports should be outlawed.
= --
= George Thiruvathukal

I wouldn't be so hasty.  Mutual importation is not frequent but is still
legitimate.  For example, consider an object-oriented system in which
classes are implemented by modules.  It is perfectly legitimate for two
classes to exchange messages and thus, do mutual importation.  It is also
legitimate for each module/class to initialize itself.  However, it still
does not seem practical for either one of the two module to reference the
other during initialization (i.e., each create an instance of the other
during initialization).  Even that may be correct (actually, not lead to
potential nondeterminism) if no reference uses information set at
initialization.

The bottom line is that one should not disparage a construct just because
one does not see a use for it.  This particular construct does lead to
an insecurity, but Modula-2 (for all of its typechecking, et.al) has
many others.

Tom Reid  (Reid@ctc.contel.com)

gkt@iitmax.iit.edu (George Thiruvathukal) (05/17/91)

In article <9105161749.AA06495@ctc.contel.com>, reid@CTC.CONTEL.COM (Tom Reid x4505) writes:

>                                      It is perfectly legitimate for two
> classes to exchange messages and thus, do mutual importation.  It is also
> legitimate for each module/class to initialize itself.

> The bottom line is that one should not disparage a construct just because
> one does not see a use for it.

Actually, I saw the "use" for it, but I disagree with the notion that the "use"
is all that useful.  Modules which are so tightly coupled should be collapsed
onto one module.  On further examination, I would suggest that what ought to be
disallowed are cycles which arise in the "import" graphs (whose nodes are both
definition and implementation modules) and edges are "imports."  Thus, two 
different modules (implementation parts) can borrow definitions and procedures
from each other.  However, their definition modules cannot do the same. It goes
without saying that this restriction is NOT severe, because there are no
mechanisms in Modula-2 for conditional compilation.

Thanks for your comments.  It is somewhat refreshing to see some positive and
scientific discussion occurring in this newsgroup.

-- 
George Thiruvathukal

Laboratory for Parallel Computing and Languages
Illinois Institute of Technology
Chicago

news@m2xenix.psg.com (Randy Bush) (05/18/91)

gkt@iitmax.iit.edu (George Thiruvathukal) writes:

> I would suggest that what ought to be disallowed are cycles which arise in
> the "import" graphs (whose nodes are both definition and implementation
> modules) and edges are "imports."  Thus, two different modules
> (implementation parts) can borrow definitions and procedures from each other.

Watch out.  Their initialization bodies should not depend on [ procedures which
use or ] values provided by the other.  This is non-trivial to detect, even
without worrying about type transfer and other sinful acts.
-- 
Randy Bush  / news@psg.com  / ..!uunet!m2xenix!news