------------------------------------------------------------------------------
Date:    Sat, 1 Sep 90 22:42:57 met
From:    Piet van Oostrum <piet@cs.ruu.nl>
Subject: Patches for HP version of m3

These patches are to get the Modula-3 compiler working on HP-UX:

1. The toplevel makefile is missing a line SHELL=/bin/sh
2. sed on SYSV systems does print substituted lines only with -n. Besides
that the parentheses in the command for imake in the makefile are
superfluous, so I changed this to:

imake: FRC
	@cd util; \
	   cpp=`cat config | sed -n -e 's/^CPP[ \t]*=[ \t]*//p' -e 'd'`; \
	   cc=`cat config | sed -n -e 's/^CC[ \t]*=[ \t]//p' -e 'd'`; \
	   sed -e s+M3_CPP+$$cpp+ imake.c > imake.foo.c; \
	   $$cc  -o imake imake.foo.c; \
	   /bin/rm -f imake.foo.c

3. The file util/install.HP300 should have mode rx. 

4. config.dist-HP300 should have CLINKFILES = -lm -lBSD


*** M3Runtime.c.~1~	Mon Jul 23 20:53:23 1990
--- M3Runtime.c	Thu Jul 26 10:17:57 1990
***************
*** 59,67 ****
  
  #if defined (HP300)
  #include <string.h>
  #endif
  
- #include <strings.h>
  #include <limits.h>
  
  #include <sys/file.h>
--- 59,68 ----
  
  #if defined (HP300)
  #include <string.h>
+ #else
+ #include <strings.h>
  #endif
  
  #include <limits.h>
  
  #include <sys/file.h>

The intermediate compiler m3.local (and I guess also m3.cross) do miss the
needed -lBSD on the link phase on HP-UX. This can be corrected (valid on
all systems by patching system/driver/Imakefile:

*** Imakefile.~1~	Mon Jul 23 20:53:18 1990
--- Imakefile	Thu Jul 26 11:00:15 1990
***************
*** 16,22 ****
  	    -e 's+PASS2+.ROOT/system/loader/m3ld+' \
  	    -e 's+DEFPATH+-D -D.ROOT/system/corelib/Interfaces -D.+' \
  	    -e 's+LIBPATH+-L.ROOT/system/corelib+' \
! 	    -e 's+LINKFILES+.ROOT/system/runtime/m3run.o -lm3core -lm+' \
  	    -e 's+LINKCOVER+.ROOT/tools/coverage/report_coverage.o+' \
  	    -e 's+INCLDIR+.ROOT/system/runtime+' \
  	    -e 's+LD_WANTS_SPACE_AFTER_L+$(LD_WANTS_SPACE_AFTER_L)+' \
--- 16,22 ----
  	    -e 's+PASS2+.ROOT/system/loader/m3ld+' \
  	    -e 's+DEFPATH+-D -D.ROOT/system/corelib/Interfaces -D.+' \
  	    -e 's+LIBPATH+-L.ROOT/system/corelib+' \
! 	    -e 's+LINKFILES+.ROOT/system/runtime/m3run.o -lm3core $(CLINKFILES)
+' \
  	    -e 's+LINKCOVER+.ROOT/tools/coverage/report_coverage.o+' \
  	    -e 's+INCLDIR+.ROOT/system/runtime+' \
  	    -e 's+LD_WANTS_SPACE_AFTER_L+$(LD_WANTS_SPACE_AFTER_L)+' \
***************
*** 30,36 ****
  	    -e 's+PASS2+.ROOT/.cross/loader/m3ld+' \
  	    -e 's+DEFPATH+-D -D.ROOT/.cross/corelib/Interfaces -D.+' \
  	    -e 's+LIBPATH+-L.ROOT/system/corelib+' \
! 	    -e 's+LINKFILES+.ROOT/.cross/runtime/m3run.o -lm3core -lm+' \
  	    -e 's+LINKCOVER+.ROOT/tools/coverage/report_coverage.o+' \
  	    -e 's+INCLDIR+.ROOT/.cross/runtime+' \
  	    -e 's+LD_WANTS_SPACE_AFTER_L+$(LD_WANTS_SPACE_AFTER_L)+' \
--- 30,36 ----
  	    -e 's+PASS2+.ROOT/.cross/loader/m3ld+' \
  	    -e 's+DEFPATH+-D -D.ROOT/.cross/corelib/Interfaces -D.+' \
  	    -e 's+LIBPATH+-L.ROOT/system/corelib+' \
! 	    -e 's+LINKFILES+.ROOT/system/runtime/m3run.o -lm3core $(CLINKFILES)
+' \
  	    -e 's+LINKCOVER+.ROOT/tools/coverage/report_coverage.o+' \
  	    -e 's+INCLDIR+.ROOT/.cross/runtime+' \
  	    -e 's+LD_WANTS_SPACE_AFTER_L+$(LD_WANTS_SPACE_AFTER_L)+' \

util/clone.c needs a few adaptions:

*** clone.c.~1~	Mon Jul 23 20:51:03 1990
--- clone.c	Thu Jul 26 11:14:05 1990
***************
*** 12,18 ****
  #include <errno.h>
  #include <stdio.h>
  
! #if defined (AIX386)
  #define gd_name d_name
  #endif
  
--- 12,18 ----
  #include <errno.h>
  #include <stdio.h>
  
! #if defined (AIX386) | defined (HP300)
  #define gd_name d_name
  #endif
  
***************
*** 204,210 ****
  	  fn (current_dir->path, file->gd_name,
  	      current_dir->depth + 1, &statbuf); }}}
      
! #if defined(IBMRT)
      closedir (dir);}  /* Doesn't return anything on IBM/4.3 */
  #else   
      if (closedir (dir) != NULL) {
--- 204,210 ----
  	  fn (current_dir->path, file->gd_name,
  	      current_dir->depth + 1, &statbuf); }}}
      
! #if defined(IBMRT) | defined (HP300)
      closedir (dir);}  /* Doesn't return anything on IBM/4.3 */
  #else   
      if (closedir (dir) != NULL) {

Analyze_coverage has a slight misspelling.

*** analyze_coverage.c.~1~	Mon Jul 23 20:51:39 1990
--- analyze_coverage.c	Thu Jul 26 23:15:13 1990
***************
*** 11,17 ****
  #include <sys/stat.h>
  #include <sys/file.h>
  #if defined (HP300)
! #include <strings.h>
  #endif
  #include <stdio.h>
  
--- 11,17 ----
  #include <sys/stat.h>
  #include <sys/file.h>
  #if defined (HP300)
! #include <string.h>
  #endif
  #include <stdio.h>
  
Piet* van Oostrum, Dept of Computer Science, Utrecht University,
Padualaan 14, P.O. Box 80.089, 3508 TB Utrecht, The Netherlands.
Telephone: +31-30-531806   Uucp:   uunet!mcsun!ruuinf!piet
Telefax:   +31-30-513791   Internet:  piet@cs.ruu.nl   (*`Pete')

------------------------------------------------------------------------------
Date:    Mon, 3 Sep 90 18:08:02 MET DST
From:    Thomas Roemke <modula-3@uni-paderborn.de>
Subject: Question about BRANDED



I've got a question about brands. The report says:
	'All brands in a program must be distinct'

Does that mean all brands in a module have to be distinct
or does that mean all brands in all modules of a program
have to be distinct ?

I got a little bit confused, because m3 compiles the following 
program without warnings and the executable doesn't raise an exception: 

MODULE a
	EXPORTS Main;

	TYPE b = BRANDED "string" REF INTEGER;
	TYPE d = BRANDED "string" REF INTEGER;

VAR a: b;
    c: d;
BEGIN
      a := c;
END a.

Is the program correct ?

Have 'a' and 'c' the same type ?



Thomas


-- 
(*	Thomas Roemke, University Paderborn, FRG
	modula-3@uni-paderborn.de
	..!uunet!mcsun!unido!pbinfo!modula-3	*)

------------------------------------------------------------------------------
Date:    Mon, 3 Sep 90 23:55:38 -0400
From:    lauri@svax.cs.cornell.edu (Georges Lauri)
Subject: src modula-3 on the NeXT

has anyone brought up src modula-3 (1.5) on a NeXT machine
and would you be willing to share the result, or, do you
have some estimate on how difficult this would be? (I'm
thinking of the threads stuff, in particular).

also, if you've used Modula-3 for a course, we'd be interested
in handouts/tips for semi-naive users that people may have written
and be willing to share.

Georges Lauri
lauri@svax.cs.cornell.edu

------------------------------------------------------------------------------
Date:    Tue, 04 Sep 90 11:38:54 PDT
From:    Eric Muller <muller@src.dec.com>
Subject: August m3 mailing list archive available


The mail archive for the messages sent to the m3 mailing list during
the month of August is available via anonymous ftp from
gatekeeper.dec.com, in pub/DEC/Modula-3/m3-mail.08-90.Z.

Eric Muller.

------------------------------------------------------------------------------
System Research Center - 130 Lytton Av. - Palo Alto, CA 94301 - (415) 853 2193

------------------------------------------------------------------------------
Date:    6 Sep 1990 0833-PDT (Thursday)
From:    <kalsow@src.dec.com>
Subject: Re: Question about BRANDED

> I've got a question about brands. The report says:
> 	'All brands in a program must be distinct'
> 
> Does that mean all brands in a module have to be distinct
> or does that mean all brands in all modules of a program
> have to be distinct ?

All brands in a program must be distinct.  Otherwise, it would be 
possible to "guess" the brand and structure of an opaque type and 
declare a visible type with the same brand and structure.  This new 
type exposes the structure of the opaque type and hence clients of 
the new type could violate the invariants of the otherwise opaque 
type.

> MODULE a
> 	EXPORTS Main;
> 
> 	TYPE b = BRANDED "string" REF INTEGER;
> 	TYPE d = BRANDED "string" REF INTEGER;
> 
> VAR a: b;
>     c: d;
> BEGIN
>       a := c;
> END a.

This program is illegal and our compiler is buggy.

Thanks for the bug report.

  - Bill Kalsow

------------------------------------------------------------------------------
Date:    Mon, 10 Sep 90 16:45:08 EDT
From:    harbison@tartan.com (Samuel Harbison)
Subject: Language question, stmt sequences

A minor language question, from the revised report.

In the "Statements" section, a statement can be a "sequence of statements."
However, in the collected syntax, "sequence of statements" (Stmts) is
not a statement, but rather Stmts is used explicitly in the places a
sequence is expected, e.g., IF e THEN Stmts END.  As far as I can tell,
the only effect of the different description is the interpretation of
multiple semicolons:

	IF e THEN
	  ;;;
	END

Would this be legal or illegal?

Sam

P.S.  RCHING: I got your message, too.

------------------------------------------------------------------------------
Date:    11 Sep 90 09:59:46 +0100 (Tuesday)
From:    Dick Snow <C.R.Snow@newcastle.ac.uk>
Subject: Re: RCHING's message.

Like Eliot Moss, I feel rather irritated at having to plough through (and then
immediately delete) a number of messages of the form :I got your message:,
especially as this time they were preceded by a :Please remove me from the
list: message (about which there was a certain amount of discussion some months
ago). E-mail etiquette (if such a thing exists) surely requires users of the
system to be more considerate in their generation of messages which cause at
best irritation, and at worst offence. In some cases, including my own, such
messages also have to cross the Atlantic, which seems a considerable waste of
resource.
Because of some vagaries of the e-mail delivery systems, the *last* message I
received was RCHING's message itself, and, after what had gone before, I was
surprised to find that it had no content! Maybe it was the cumulative
irritation built up over the previous few messages, but I did feel that it
would have been nice to know who RCHING was, and why he(she?) wanted the whole
of the 'm3' distribution list to reply to him/her. Surely if his/her purpose is
to find out who is on the list, it would be simpler for all concerned if s/he
merely asked DEC/SRC to supply a copy. If s/he has some other reason for
generating a potentially large quantity of e-mail traffic, I, and possibly
others, would be very interested to know what it is.
			... Dick Snow.

	C. R. Snow
	Computing Laboratory
	University of Newcastle upon Tyne
	Newcastle upon Tyne,
	NE1 7RU,
	U.K.

	C.R.Snow@newcastle.ac.uk

------------------------------------------------------------------------------
Date:    Wed, 12 Sep 90 10:30:29 EDT
From:    harbison@tartan.com (Samuel Harbison)
Subject: A programming quiz, in Modula-3

Here's a little problem to occupy your spare minutes.  Everyone submitting a
correct answer by Saturday (9/15) midnight will get their names mentioned in a
BBoard message that will also feature the best correct answer.  Reply to
me, of course, so those other people can't cheat and get a share of the prize.

We all know how FOR loops are supposed to work.  I used to work for a compiler
company that had a lot of bright people in it, and we wrote a Modula-2
compiler that was pretty nice.  One day, a user called in to say that our FOR
loops were broken.  He was iterating up to LAST(INTEGER), and we got it wrong.

On page 26 of the Modula-3 Report (revised) is a rewriting of the Modula-3 FOR
statement that has the same mistake we had: if delta>0 and last=LAST(INTEGER),
INC(i,delta) will overflow after the "last" iteration and the loop will never
terminate.  (Or, if overflow checking were enabled, an error would occur.)

PROBLEM: Rewrite the rewriting to work correctly for all values of first,
last, and step.


------------------------------------------------------------------------------
Date:    Thu, 13 Sep 90 07:09:31 EDT
From:    Dave Hanson <drh@Princeton.EDU>
Subject: A programming quiz, in Modula-3

   Date: Wed, 12 Sep 90 10:30:29 EDT
   From: harbison@tartan.com (Samuel Harbison)
   Reply-To: harbison@tartan.com

   Here's a little problem to occupy your spare minutes.  Everyone submitting a
   correct answer by Saturday (9/15) midnight will get their names mentioned in
 a
   BBoard message that will also feature the best correct answer.  Reply to
   me, of course, so those other people can't cheat and get a share of the priz
e.

   We all know how FOR loops are supposed to work.  I used to work for a compil
er
   company that had a lot of bright people in it, and we wrote a Modula-2
   compiler that was pretty nice.  One day, a user called in to say that our FO
R
   loops were broken.  He was iterating up to LAST(INTEGER), and we got it wron
g.

   On page 26 of the Modula-3 Report (revised) is a rewriting of the Modula-3 F
OR
   statement that has the same mistake we had: if delta>0 and last=LAST(INTEGER
),
   INC(i,delta) will overflow after the "last" iteration and the loop will neve
r
   terminate.  (Or, if overflow checking were enabled, an error would occur.)

   PROBLEM: Rewrite the rewriting to work correctly for all values of first,
   last, and step.

M. C. Newey and W. M. Waite,
The Robust Implementation of Sequence-Controlled Iteration,
{\it Software---Practice \& Experience \bf 15}, 7 (July 1985) 655-668.

------------------------------------------------------------------------------
Date:    Thu, 13 Sep 90 08:13:39 EDT
From:    moss%ibis@cs.umass.edu (Eliot Moss)
Subject: A programming quiz, in Modula-3

I asked about this some time ago (FOR loops going to the end of the integer
range) and the response I got was:

o Overflow is *supposed* always to result in an error in Modula-3, though this
  *may* not be true in the C based compilers (SRC, Olivetti) because it is
  just too costly to check integer operations for overflow through C.

o Therefore, in the rare instances in which people might try to go to
  LAST(INTEGER), too bad, it will overflow; the designers stand by the
  rewriting, since other approaches are more complex and (in the general case)
  slower. The users can rewrite such loops themselves using WHILE or whatever.

In the GNU M3 compiler effort we have yet to deal with integer overflow,
though we are clearly in a better position to do so than the C output
compilers. I am uncertain as to the best course to take, however, since
following the language spec precisely will result in some slow down when
compared with C/C++, which might impede acceptance of M3. We could always go
the compiler switch route, but that goes against the philosophy of the
language, too.

Actually, the FOR loop case is not too bad for two popular targets, namely the
VAX and the MIPS R2000. The VAX has a special loop increment instruction which
will detect the overflow, and the MIPS has two flavors of add instruction, one
that traps overflow and one that does not, so we can just insure that the
overflow trapping instruction is used. However, this may all potentially
interfere with other optimizations, such as strength reduction (replacement of
FOR i ... DO ... A[i] ... END with a stepping pointer as in the C form *p++),
though if folded properly with array bounds detection, it should not be too
bad (i.e., we're morelikely to run off the end of the array than out of the
range of i, in most cases). We also have a general concern about doing a good
job on range/bounds checking. It is too early for us to say what the penalty
will be for "typical" code; perhaps the compiler really will be good enough to
optimize most of the checks away, and it appears that a soon to be released
new version of gcc will have more support for this.

The FOR loop as designed for M3 probably represents a reasonable tradeoff
between a clean definition and what can be done nicely with existing hardware
capabilities. As a side note, if one wants to optimize to byte or 16-bit word
operations, then it is not just LAST(INTEGER) that is a problem, but also 255
and 32767, etc.

Further thoughts, reactions, etc., on this issue? Advice from the designers on
what I should do in my compiler? Clarification of what the SRC and Olivetti
compilers do?
							Eliot

		J. Eliot B. Moss, Assistant Professor
		Department of Computer and Information Science
		Lederle Graduate Research Center
		University of Massachusetts
		Amherst, MA  01003
		(413) 545-4206; Moss@cs.umass.edu

------------------------------------------------------------------------------
Date:    Thu, 13 Sep 1990 09:10:28 -0500 (CDT)
From:    Dick Orgass <orgass@rchland.ibm.com>
Subject: Moving SRC Modula-3

I recently found it necessary to move the source tree for SRC Modula-3
to a different location and to prepare the compiled system for
distribution to other sites via streaming tape.  This turns out to be
quite simple and this note describes the procedure I used in case it's
useful to others.

I moved the build tree for a RISC 6000 system (IBMR2) but the steps are
the same for other systems.

(1)	Before or after moving the tree, in the target specific directory
(IBMR2.obj in my case), execute the following commands:

    rm .SRC
    ln -s ../dist-1.5 .SRC

(2)	In the target specific directory, execute the shell script
update-move which appears below.  Before executing the shell script,
change the occurrence of IBMR2 on the last line to your target.

	When this shell script is executed, the symbolic links for the
interfaces are removed and all of the installation directory specific
files are deleted.  The make at the end reinstalls the symbolic links
for the interfaces.

(3)	To build the system for new directories, execute the command

    make -k

in the target specific directory.


Dick

----------------------- file update-move ------------------
#! /bin/csh -f
rm ./libs/io/Interfaces/*.i3
rm ./libs/Xt/Interfaces/*.i3
rm ./libs/math/Interfaces/*.i3
rm ./libs/misc/Interfaces/*.i3
rm ./libs/Xlib/Interfaces/*.i3
rm ./libs/Xaw/Interfaces/*.i3
rm ./libs/ultrix-3.1/Interfaces/*.i3
rm ./libs/data/Interfaces/*.i3
rm ./libs/aix-ps2-1.2/Interfaces/*.i3
rm ./libs/ibm-4.3/Interfaces/*.i3
rm ./libs/aix-3.1/Interfaces/*.i3
rm ./libs/posix/Interfaces/*.i3
rm ./libs/hpux-7.0/Interfaces/*.i3
rm ./system/compiler/Interfaces/*.i3
rm ./system/corelib/Interfaces/*.i3
rm ./system/driver/m3
rm ./system/driver/m3.local
rm ./system/driver/m3.1
rm ./system/loader/m3ld
rm ./tools/depend/m3imc
rm ./tools/depend/m3imc.1
rm ./tools/pp/m3pp
rm ./tools/pp/m3pp.1
rm ./tools/coverage/analyze_coverage
rm ./tools/coverage/analyze_coverage.1
rm ./tools/coverage/coverage.5
rm ./tools/coverage/coverage.7
make -k IBMR2
---------------------end------------------------

------------------------------------------------------------------------------
Date:    Fri, 14 Sep 90 09:03:29 EDT
From:    harbison@tartan.com (Samuel Harbison)
Subject: FOR loops (intentional and otherwise)

Part 1...

I was mildly chastised for suggesting the FOR loop description on p. 26 was in
error, when in fact it represented the intent of the designers.  The
motivation for the design decision was a desire not to penalize the efficiency
of all programs just to handle a boundary case that never happens anyway.
(You can always rewrite the FOR as a WHILE yourself if this is a problem.)

So, it appears that the description of the FOR loop in the report could be
"clarified" by adding something like the following to p. 25 (so that
people don't mis-implement it):

"In Modula-3, it is a checked runtime error to complete the last iteration of
a FOR loop in which 
	delta>0 AND ORD(last)+delta > LAST(INTEGER).  
Similarly, it is a checked runtime error to complete the last iteration if
	delta<0 AND ORD(last)-delta < FIRST(INTEGER)."
I'm not absolutely sure the equation is correct, but you get the idea.

If any members of the langauge committee think this is not the current
definition, please tell me soon.  In particular, do implementations have the
option to NOT generate an error?  (That is not what the report says, but I
know of at least one east coast M3 implementor who seems to think it's OK...)

Part 2...

Well, I don't much like this, so I called one of the chief code generator
gurus at Tartan Laboratories to make sure I wasn't just getting old and
cranky.  (Well, on this issue, anyway.)  TL develops optimizing compilers for
a variety of architectures, and they have to handle the boundary cases for
their languages (C, Modula-2, and Ada) since it appears that users do
occasionaly write such code. (The Ada validation suite checks it, of course.
Probably the C ones do also.)

The report from TL was: Some architectures handle the boundary cases with no
penalty, and some do not.  On the VAX, which does not, it takes about one
extra cycle to handle it.  In any case, they said, it didn't seem like a big
enough deal to affect a language definition.

I agree.  Especially in a language that already checks for arithmetic overflow
and encourages garbage collection.

OK, 'nuff said.  Back to work...

Sam Harbison
------------------------------------------------------------------------------
Pine Creek Software, 305 S. Craig St., Suite 300, Pgh, PA 15213. 412-681-9811

------------------------------------------------------------------------------
Date:    Fri, 14 Sep 90 15:49:34 -0400
From:    fkz@cs.brown.edu (Kenneth Zadeck)
Subject: HALT statement 

I noticed in the interface for ParseParams that there was a HALT
statement.  Is this a local extension or is this part of the language?
I could not find it in the revised report.

kenny

------------------------------------------------------------------------------
Date:    Fri, 14 Sep 90 17:59:26 PDT
From:    Eric Muller <muller@src.dec.com>
Subject: Re: HALT statement 


> I noticed in the interface for ParseParams that there was a HALT
> statement.  Is this a local extension or is this part of the language?
> I could not find it in the revised report.

The HALT statement is in a comment showing an actual use of the
ParseParams interface. 

It turns out that this interface has been translated from a Modula-2+
version, and I have not been very careful. The line should read 

    Cstdlib.exit (-1);

You have certainly noticed that the syntax of the TRY EXCEPT statement
is also wrong. It should be:

     TRY 
       ...
     EXCEPT
     | Scan.BadFormat =>
         ...
     END;

Sorry for the confusion this may have caused.

Eric Muller.

------------------------------------------------------------------------------
System Research Center - 130 Lytton Av. - Palo Alto, CA 94301 - (415) 853 2193

------------------------------------------------------------------------------
Date:    Mon, 17 Sep 90 15:55 +1000
From:    Richard Thomas <R_Thomas@qut.edu.au>
Subject: Re: FOR loops (intentional and otherwise)

IN%"harbison@tartan.com" 16-SEP-1990 00:31:17.69 writes:
Well, I don't much like this, so I called one of the chief code generator
gurus at Tartan Laboratories to make sure I wasn't just getting old and
cranky.  (Well, on this issue, anyway.)  TL develops optimizing compilers for
a variety of architectures, and they have to handle the boundary cases for
their languages (C, Modula-2, and Ada) since it appears that users do
occasionaly write such code. (The Ada validation suite checks it, of course.
Probably the C ones do also.)

The report from TL was: Some architectures handle the boundary cases with no
penalty, and some do not.  On the VAX, which does not, it takes about one
extra cycle to handle it.  In any case, they said, it didn't seem like a big
enough deal to affect a language definition.

I agree.  Especially in a language that already checks for arithmetic overflow
and encourages garbage collection.
	
	I also agree.  Just a couple of weeks ago we looked at this
	problem in my Compiler Construction class in relation to avoiding
	this error in an M2 compiler we wrote here.  The overhead to
	do the checks is pretty minimal especially if you have a smart
	compiler and do a little arithmetic.  I think it is a poor design
	that puts in a cheat like this just to avoid a little extra work
	for the compiler.  The definition for the FOR loop as it stands
	is unnatural and awkward for intuitively correct code.

Au revoir,

@~~Richard Thomas  aka. The AppleByter  --  The Misplaced Canadian~~~~~~~~~~~@
{ InterNet: R_Thomas@qut.edu.au           ACSNet:  richard@earth.qitcs.oz.au }
{ PSI:      PSI%505272223015::R_Thomas                                       }
@~~~~~School of Computing Science - Queensland University of Technology~~~~~~@

------------------------------------------------------------------------------
Date:    Mon, 17 Sep 90 16:18:35 EDT
From:    harbison@tartan.com (Samuel Harbison)
Subject: Answers to quiz...

Well, NO ONE sent any code for the FOR loop, but here are two references.

Jeff Woolsey of Microtec Research, Inc. recommends the code in Wirth's
Programming in Modula-2/3e.  [I couldn't find a page reference. -sh]

Dave Hanson at Princeton cites M. C. Newey and W. M. Waite, The Robust
Implementation of Sequence-Controlled Iteration, {\it Software---Practice \&
Experience \bf 15}, 7 (July 1985) 655-668.

Thanks for the contributions.  Did I mention I had planned to give out $1,000
for the best code?  No?  Oh, well, too late now...

Sam

------------------------------------------------------------------------------
Date:    Tue, 18 Sep 90 10:43:58 EDT
From:    eachus@d74sun.mitre.org (Robert I. Eachus)
Subject: FOR loops (intentional and otherwise)

     We just had a discussion of this precise issue in the ARG (the
Ada standard maintenance group).  The issue will be reconsidered when
written in final form, but for now it looks like:

     A loop with one static or dynamic bound which is INTEGER'FIRST or
INTEGER'LAST must work "correctly," but a loop from INTEGER'FIRST to
INTEGER'LAST is a pathological case which need not be considered.

     In other words, since there is an easy way in Ada to write loop
forever, there is no need to write the nasty code to loop over all
values of the largest useful index type so that it executes exactly
2**32 times.  A programmer can "unroll" explicitly one iteration where
necessary to avoid getting junk code for all dynamic loops.

     Keep in mind that this is a very preliminary reading of the
recommendation and in may change, particularly for cases where
SYSTEM.MAX_INT /= INTEGER'LAST.


					Robert I. Eachus

with STANDARD_DISCLAIMER;
use  STANDARD_DISCLAIMER;
function MESSAGE (TEXT: in CLEVER_IDEAS) return BETTER_IDEAS is...


------------------------------------------------------------------------------
Date:    Fri, 14 Sep 90 11:52:41 MET DST
From:    Thomas Roemke <modula-3@uni-paderborn.de>
Subject: Question about enum variables



Suppose you have a declaration

VAR enum: {a,b,c,d,e};

Since there's no visible enum type, 
how can one assign enum a value ?  

Thomas

P.S.: Of course, it's possible to define a type T = {a,b,c,d,e}, declare
      VAR enum: T  and there's no problem.........

-- 
(*	Thomas Roemke, University Paderborn, FRG
	modula-3@uni-paderborn.de
	..!uunet!mcsun!unido!pbinfo!modula-3	*)

------------------------------------------------------------------------------
Date:    Tue, 18 Sep 90 12:58:04 EDT
From:    moss%ibis@cs.umass.edu (Eliot Moss)
Subject: Question about enum variables

Well, it *is* inconvenient not to give an enum type a name, but with FIRST,
LAST, and more generally, VAL, you *can* construct the values of the type
without reference to the names. There may be occasions where a construct
TYPEOF(exp) would be useful, allowing reference to the type of a variable (for
example). If M3 had that, you could write TYPEOF(v).a and stuff. I suspect one
cannot make strong arguments for TYPEOF in the absence of a generics /
paramaterization facility, though.				Eliot

		J. Eliot B. Moss, Assistant Professor
		Department of Computer and Information Science
		Lederle Graduate Research Center
		University of Massachusetts
		Amherst, MA  01003
		(413) 545-4206; Moss@cs.umass.edu

------------------------------------------------------------------------------
Date:    18 Sep 1990 1040-PDT (Tuesday)
From:    <gnelson@src.dec.com>
Subject: Re: Question about enum variables


Thomas Roemke asks:

    Suppose you have a declaration
    
    VAR enum: {a,b,c,d,e};
    
    Since there's no visible enum type, 
    how can one assign enum a value ?  

The answer is that you could say

    enum := {a,b,c,d,e}.a

if you really wanted to leave the type anonymous.  But why you would
want to do this is beyond me.

Greg

------------------------------------------------------------------------------
Date:    18 Sep 1990 1223-PDT (Tuesday)
From:    <stolfi@src.dec.com>
Subject: Re: Question about enum variables


    [Greg:] But why you would want to [leave an enumeration type
    anonymous] is beyond me.
    
Because inventing names is a nuisance.  M3's structural type equivalence
thankfully removed this need from many contexts, and naturally made
the few remaining ones to stand out like sore thumbs. 

I stumbled into the same M3 quirk the other day, when I wrote

  PROCEDURE Sort(VAR a: ARRAY OF T; order: {Increasing, Decreasing});

After the "oops", it took some time to convince myself that 
anonymous enumeration types are virtually useless in M3.
Here are some possible solutions to this "problem" that 
occurred to me then:

  Solution 1:
      If the type of <expr> is an enumeration type T, then 
      define <expr>.<id> to mean the same as T.<id>
  
  Solution 2:
      Introduce the pseudo-procedure TYPEOF(<expr>), which returns the
      type of the designated expression.  Then one could write
  
         option := TYPEOF(option).Foo
  
      Note that since the type of <expr> is known at compile-time, the 
      meaning of TYPEOF(<expr>) would be similarly known.
      Which means one could use TYPEOF in any context where a type
      would be acceptable:
  
         TYPE T = TYPEOF(y);
         
         VAR x: TYPEOF(y);
            
         rx := NEW(TYPEOF(rx)); 

      Reversing Eliot Moss' argument, the TYPEOF construct may be quite
      handy once M3 generics become available.
  
  Solution 3:
      Let the values of enumerations be *unqualified* global symbols,
      enclosed in single quotes.  That is, one should write
  
          TYPE 
            Color = { 'Red',  'Yellow',  'Green', 'Cyan', 
                      'Blue', 'Magenta', 'White', 'Black' };
            TrafficLight = { 'Green', 'Yellow', 'Red' };
            Maturation = { 'Green', 'Ripe'}
            Operator = { '+', '*', '%%' };

      Note that the 'Green' of Color is the same value as the 'Green'
      of Maturation. So, for example:
  
          VAR
            color: Color;
            trfic: TrafficLight;
            mtion: Maturation;
            i: INTEGER;
  
          color := 'Green';            (* Ok *)
          color := 'Ripe';             (* Range error (detectd at compile time)
 *)
          color := VAL(2, Color);      (* Ok, means 'Green' *)
          color := VAL(0, Maturation); (* Ok, means 'Green' *)
          
          i := ORD('Green', Color);        (* Ok, means 2 *)
          i := ORD('Green', TrafficLight); (* Ok, means 0 *)
          i := ORD('Green');               (* Syntax error, ORD requires 2 args
 *)
  
          color := trfic;   (* Ok, uses a translation table *)
          trfic := color;   (* Ok, uses a translation table w/ "invalid" flags 
*) 
          trfic := mtion;   (* Ditto, but also emits a level 2 warning: 
                               "source type is neither a subset nor a superset
                                of target type" *)
          color := VAL(i, Maturation); (* Ditto *)
  
      Note that the ' ' notation for CHAR literals would then be a
      special case of this rule, except for the octal escapes.  (As for
      these, perhaps no one will really miss '\011', given that they
      can write 'TAB' and VAL(8_011, CHAR).  (If they really make a fuss
      about it, perhaps EnumType[i] can be defined as syntactic sugar
      for VAL(i, EnumType).).)

      Additional repercussions of this proposal are left as an exercise
      to the reader 8-)
            
--jorge

------------------------------------------------------------------------------
Date:    19 Sep 1990 0814-PDT (Wednesday)
From:    <kalsow@src.dec.com>
Subject: Re: Method override 

> >>  TYPE
> >>    T = OBJECT METHODS whoami() := FooT END;
> >>    A = T OBJECT data: INTEGER METHODS whoami := FooA  END;
> >>    B = T OBJECT data: REAL METHODS whoami := FooB END;

> >>  prl304 240> Test1
> >>   T
> >>   A
> >>   B

No surprises.

> >>  TYPE
> >>    T = OBJECT METHODS whoami() := FooT END;
> >>    A = T OBJECT METHODS whoami := FooA  END;
> >>    B = T OBJECT METHODS whoami := FooB END;

> >>  prl304 241> Test2
> >>   T
> >>   B
> >>   B

The compiler identified types A and B, because it ignored
the default values of the methods.  This is a compiler bug.
The compiler then picked B as the representative for the "single" type.

(Eric, is this bug fixed in your version?)

> >>  TYPE
> >>    T = OBJECT METHODS whoami() := FooT END;
> >>    A = T OBJECT data: INTEGER METHODS whoami := FooA  END;
> >>    B = T OBJECT data: INTEGER METHODS whoami := FooB END;
> 
> >>  prl304 242> Test3
> >>   T
> >>   B
> >>   B

Again, the compiler ignored FooA and FooB and went on to identify
the types.

> >>  TYPE
> >>    T = OBJECT METHODS whoami() := FooT END;
> >>    A = T OBJECT dataA: INTEGER METHODS whoami := FooA  END;
> >>    B = T OBJECT dataB: INTEGER METHODS whoami := FooB END; 

> >>  prl304 243> Test4
> >>   T
> >>   A
> >>   B

The field names dataA and dataB are differenct so the compiler
kept types A and B distinct.

> Finally, I swapped the order of the top level procedures FooA and FooB in 
> the source file for Test2, the code for Test5.m3 is thus:
> which gives:

> >>  prl304 244> Test5
> >>   T
> >>   A
> >>   A

The compiler bug that identifies types A and B picks one
of them more or less randomly.  In this case it picked A,
previously it was taking B.

  - Bill

------------------------------------------------------------------------------
Date:    Wed, 19 Sep 1990 10:45:54 -0500 (CDT)
From:    Dick Orgass <orgass@rchland.ibm.com>
Subject: AIX 3.1 correction, proposed target specific library additions

The purpose of this note is to provide a correction for the AIX 3.1
version of Unix.i3, to propose an addition to Uerror.i3 and to propose
the addition of an interface and module to the target specific libraries.

libs/aix-3.1/Interfaces/Unix.i3

File released as ../lib/m3/aix-3.1/Unix.i3

AIX 3.1 can be thought of as having three modes: 4.3 BSD, SystemV and
AIX.  The declaration of struct_stat, etc at lines 929-966 is
appropriate for AIX mode and, perhaps, for SystemV mode but it is not
appropriate for BSD mode.  Modula-3 source is compiled in BSD mode.  I
did make the correction for BSD mode in CoreOS.i3 but forgot to make it
in Unix.i3.  The interface Stat.i3, below, is a correct replacement for
the declaration of struct_stat, etc in Unix.i3.  It can be used until
the next release when the change should be installed.

Access to directory reading procedures.

The BSD directory reading procedures, opendir, readdir, etc are not
defined in the operating system interfaces.  I propose that the
interface and module Dirent, below, be added to the target specific
libraries for those targets that support these calls.  The interface
defines the appropriate types and external procedures.  In addition, I
added a procedure that converts the d_name field of a struct_dirent into
a text.  I did this because I found myself writing the code over and
over again in clients.

Converting Uerror.errno to a TEXT message

In a number of places, I found myself writing out code to look up an
error message that corresponds to an error code and converting it to
text in order to write error messages.  I propose that Uerror be
extended with a procedure, ErrorText, with the same properties as
ErrorText.FromErrno in the attached interface and module ErrorText.

Dick

(* File Stat.i3, created by Dick Orgass at 15:07:10 on Mon Sep 17 1990.
*)

(*   Copyright (C) by IBM Corporation, 1990. *)

INTERFACE Stat;
FROM Ctypes IMPORT int, short, unsigned_short, long, unsigned_long,
char_star;

(* Note that the following assumes that bsdcc is used to compile the
   C generated by the Modula-3 compiler.  *)

<*UNUSED*> CONST
  StatCopyright = "Copyright (C) by IBM Corporation, 1990.";
  StatRCSHeader = "$Header$";
  StatDate = "$Date$";
  StatRevision = "$Revision$";

(* For documentation of this interface see Calls and Subroutines
Reference: BaseOperatingSystem, Volume 1, IBM Form number SC23-2198-00,
pp 1-711 to 1-714. *)

TYPE
  dev_t = unsigned_long;
  ino_t = unsigned_long;
  off_t = long;
  time_t = long;
  uid_t = unsigned_long;
  gid_t = unsigned_long;

TYPE
  struct_stat = RECORD
     st_dev    : dev_t;
     st_ino    : ino_t;
     st_mode_ext: unsigned_short;
     st_mode   : unsigned_short;
     st_nlink  : short;
     st_pad_to_word: short;
     st_uid_ext: short;
     st_uid    : unsigned_short;
     st_gid_ext: unsigned_short;
     st_gid    : unsigned_short;
     st_rdev   : dev_t;
     st_size   : off_t;
     st_atime  : time_t;
     st_spare1 : int;
     st_mtime  : time_t;
     st_spare2 : int;
     st_ctime  : time_t;
     st_spare3 : int;
     st_blksize: unsigned_long;
     st_blocks : unsigned_long;
     st_vfstype: unsigned_long;     (* Type of fs *)
     st_vfs        : unsigned_long;  (* Vfs number *)
     st_type   : unsigned_long;  (* Vnode type *)
     st_gen    : unsigned_long;  (* Inode generation number *)
     st_flag   : unsigned_long;  (* Flag word *)
     Reserved1 : uid_t;  (* Reserved *)
     Reserved2 : gid_t;  (* Reserved *)
     st_access : unsigned_short; (* Process' access to file *)
     st_spare4 : ARRAY [0..4] OF unsigned_long; (*Reserved *)
   END;

CONST
  SIFMT   :unsigned_short = 8_10000;
  SIFPIPE          = 8_0;
  SIFPORT          = 8_1;
  SIFCHR           = 8_2;
  SIFDIR           = 8_4;
  SIFBLK           = 8_6;
  SIFREG           = 8_10;
  SIFLNK           = 8_12;
  SIFSOCK          = 8_14;

<*EXTERNAL*> PROCEDURE stat (path: char_star; VAR buf: struct_stat): int;

<*EXTERNAL*> PROCEDURE lstat (path: char_star; VAR buf: struct_stat):
int;

<*EXTERNAL*> PROCEDURE fstat (fd: int; VAR buf: struct_stat): int;

END Stat.

(* File Dirent.i3, created by Dick Orgass at 11:38:53 on Tue Sep 18
1990. *)

(*   Copyright (C) by IBM Corporation, 1990. *)

INTERFACE Dirent;
IMPORT Stat;
FROM Ctypes IMPORT char_star, int, long, unsigned_long, unsigned_short;

<*UNUSED*> CONST
  DirentCopyright = "Copyright (C) by IBM Corporation, 1990.";
  DirentRCSHeader = "$Header$";
  DirentDate = "$Date$";
  DirentRevision = "$Revision$";

(* For documentation of this interface (except NameToText) see Calls and
Subroutines Reference: Base Operating System, Volume 1, IBM Form number
SC23-2198-00, pp 1-522 to 1-524. *)

TYPE
  D_name = ARRAY [0..255] OF CHAR;
  DIR = RECORD
    dd_fd: int;
    dd_blksize: int;
    dd_buf: char_star;
    dd_size: long;
    dd_flag: long;
    dd_loc: long;
    dd_curoff: long
  END;
  DIR_star = UNTRACED REF DIR;

  struct_dirent = RECORD
    d_offset: unsigned_long;
    d_ino: Stat.ino_t;
    d_reclen: unsigned_short;
    d_namelen: unsigned_short;
    d_name: D_name;
  END;

  struct_dirent_star = UNTRACED REF struct_dirent;

<* EXTERNAL *> PROCEDURE opendir(dir: char_star): DIR_star;

<* EXTERNAL *> PROCEDURE readdir(VAR dirPtr: DIR): struct_dirent_star;

<* EXTERNAL *> PROCEDURE telldir(VAR dirPtr: DIR): long;

<* EXTERNAL *> PROCEDURE seekdir(VAR dirPtr: DIR; location: long);

<* EXTERNAL *> PROCEDURE rewinddir(VAR dirPtr: DIR);

<* EXTERNAL *> PROCEDURE closedir(VAR dirPtr: DIR);

PROCEDURE NameToText(name: D_name): TEXT RAISES {};

(* Converts the d_name field of a struct_dirent to a TEXT and returns
it.  *)

END Dirent.

(* File Dirent.m3, created by Dick Orgass at 11:49:05 on Tue Sep 18
1990. *)

(*   Copyright (C) by IBM Corporation, 1990. *)

MODULE Dirent;
IMPORT Char, Text;

<*UNUSED*> CONST
  DirentImplCopyright = "Copyright (C) by IBM Corporation, 1990.";
  DirentImplRCSHeader = "$Header$";
  DirentImplDate = "$Date$";
  DirentImplRevision = "$Revision$";

PROCEDURE NameToText(name: D_name): TEXT RAISES {} =

(* Converts the d_name field of a struct_dirent to a TEXT and returns
it.  *)

VAR
  nameLength: CARDINAL := 0;
  charName: REF ARRAY OF CHAR;
BEGIN
  FOR i := 0 TO 255 DO
    IF name[i] = Char.NUL THEN EXIT ELSE INC(nameLength) END
  END;
  charName := NEW(REF ARRAY OF CHAR, nameLength);
  FOR i := 0 TO nameLength-1 DO charName[i] := name[i] END;
  RETURN Text.FromChars(charName^)
END NameToText;

BEGIN
END Dirent.

(* File ErrorText.i3, created by Dick Orgass at 09:41:48 on Wed Sep 19
1990. *)

(*   Copyright (C) by IBM Corporation, 1990. *)

INTERFACE ErrorText;
IMPORT Ctypes;

<*UNUSED*> CONST
  ErrorTextCopyright = "Copyright (C) by IBM Corporation, 1990.";
  ErrorTextRCSHeader = "$Header$";
  ErrorTextDate = "$Date$";
  ErrorTextRevision = "$Revision$";

PROCEDURE FromErrno(errno: Ctypes.int): TEXT RAISES {};

(*  Returns sys_errlist[errno] as a TEXT.  Note that there is no
new-line (\n) at the end of the return value. *)

END ErrorText.

(* File ErrorText.m3, created by Dick Orgass at 09:46:00 on Wed Sep 19
1990. *)

(*   Copyright (C) by IBM Corporation, 1990. *)

MODULE ErrorText;
IMPORT Ctypes, Fmt, M3toC;

<*UNUSED*> CONST
  ErrorTextImplCopyright = "Copyright (C) by IBM Corporation, 1990.";
  ErrorTextImplRCSHeader = "$Header$";
  ErrorTextImplDate = "$Date$";
  ErrorTextImplRevision = "$Revision$";

(* AIX 3.1 defines errno, sys_errlist and sys_nerr (as well as perror
which is omitted here).  sys_nerr is the number of messages currently in
sys_errlist and the documentation suggests checking the error number
against this value because there may be error codes without messages in
sys_errlist some of the time.  For more details, see p. 1-259 of Calls
and Subroutines Reference: Base Operating System, Volume 1, IBM form
number SC23-2198-00 for more information. *)

<* EXTERNAL *> VAR
  sys_errlist: ARRAY [0..200] OF Ctypes.char_star;
  (* The value 200, above, is a guess to be large enough; current value
of sys_nerr is 115.  *)
  sys_nerr: Ctypes.int;

PROCEDURE FromErrno(errno: Ctypes.int): TEXT RAISES {} =

(*  Returns sys_errlist[errno] as a TEXT.  Note that there is no
new-line (\n) at the end of the return value. *)

BEGIN
  IF errno < sys_nerr THEN
    RETURN M3toC.StoT(sys_errlist[errno])
  ELSE
    RETURN "Unknown error, code = " & Fmt.Int(errno)
  END
END FromErrno;

BEGIN
END ErrorText.

------------------------------------------------------------------------------
Date:    20 Sep 1990 0808-PDT (Thursday)
From:    <stolfi@src.dec.com>
Subject: Questions about TEXT


Since TEXT is a subtype of REFANY, and NIL is a member of any REF type,
does it follow that NIL is a member of TEXT?

Is  NIL = ""  true?

Is  "" = ""  true?

Is "foo" = "foo" true?

Is Text.Equal(NIL, "") true?

If a variable of type TEXT isn't initialized explicitly, does it have
(may it have) the value NIL?  The value ""?  Some other value?

--jorge

------------------------------------------------------------------------------
Date:    20 Sep 1990 0942-PDT (Thursday)
From:    <gnelson@src.dec.com>
Subject: Re: Questions about TEXT


Jorge,

The issue of the NIL TEXT was discussed on this bboard several months
ago.  Here are the answers to your questions.  I should warn you that
there are some errors in the SRC compiler in this area; I'm giving
you the M3 language definition.

    Since TEXT is a subtype of REFANY, and NIL is a member of any REF
    type, does it follow that NIL is a member of TEXT?

A variable of type TEXT can assume the value NIL, but this value does
not represent any character string, and it is an error to pass it
to any of the procedures in the Text interface.
    
    Is NIL = "" true?

No.
    
    Is "" = "" true?

Not necessarily; it depends on how the implementation handles text
literals.
    
    Is "foo" = "foo" true?

Not necessarily; it depends on how the implementation handles text
literals.
    
    Is Text.Equal(NIL, "") true?

As explained above (and in the M# report), it is a checked runtime
error to pass NIL to any of the procedures in the Text interface.
    
    If a variable of type TEXT isn't initialized explicitly, does it
    have (may it have) the value NIL?  The value ""?  Some other value?

It can be initialized to any value that is a member of the type TEXT,
including NIL and "".  If you care about the initial value, I recommend
using an explicit initializer (e.g., ":= NIL" or ':= ""') for
readability.
 

------------------------------------------------------------------------------
Date:    20 Sep 1990 1802-PDT (Thursday)
From:    <stolfi@src.dec.com>
Subject: Re: Questions about TEXT


    > [Greg:] The issue of the NIL TEXT was discussed on this bboard
    > several months ago.

Oops, right. (How did I managed to forget that? I must be running
out of synapses...)
    
Your final message in that exchange (dated 20/Jun/90) says:

    > I see two reasonable positions:
    > 
    >     (1) The TEXT NIL represents the empty character string.
    > 
    >     (2) The TEXT NIL does not represent any character string.
    
I suppose that any position that calls for changes to the language
is /a priori/ unreasonable, right?

Otherwise, as a programmer, I would think the following alternative
to be even more reasonable:

          (3) TEXT is a primitive type on its own, like INTEGER or REAL, 
              and not a REF type.

I claim that (3) is the way most of us plain programmers think of TEXT.
Letting TEXT be an opaque REF may seem to simplify the language, but
this simplicity is illusory, since it forces all programmers to be
aware of implementation details they should not know about, and do
not want to know about.

The "Null TEXT" issue is just one example of the actual complications
that are introduced by the "simplifying" decision to let TEXT be an
opaque REF.  Another example is the fact that the "=" operator is
virtually useless for TEXT values, except as a source of subtle
programming errors.  Yet another example is the need to call a procedure
in order to fetch characters from a TEXT.  These problems could easily
be solved if TEXT were a primitive type:  NIL would obviously not be
a valid TEXT, "=" could be defined to mean Text.Equal, "<" could mean
Text.LT, and text[i]" could be used to denote the text's /i/th
character.

Saying that TEXT is a REF type also places unnecessary constrains on
the implementation.  If TEXTs were built-in types, an implementor could
choose to represent them by 64-bit variant records, containing either
the actual text, for strings up to 7 bytes long, or a REF to the same,
for longer strings.  Depending on the statistics of text lengths and
the cost of allocation+collection, this schema could be a lot more
efficient overall than the REF-only schema demanded by the Report.

Of course, you well know that my definition of a "good" programming
language is very unconventional (to say the least) and fundamentally
different from yours; which makes it hard for me to come up with
suggestions that you will find reasonable, and hard for you to come
up with arguments that I will find convincing.  So, please forgive
me for repeatedly posting "heretical" ramblings like this one, and
please don't waste too much time and energy when replying to them.

--jorge

------------------------------------------------------------------------------
Date:    Fri, 21 Sep 1990 12:17:57 -0500 (CDT)
From:    Dick Orgass <orgass@rchland.ibm.com>
Subject: Compiler Bug for Objects?

I was looking at yet another approach to declaring object types so that:

        (1)     Only the methods of the object are in the public
        interface.

        (2)     It is not possible to create a usable instance of
        the public object using NEW.  Rather, a Create procedure is
        to be used.

I declared an interface A as follows:

INTERFACE A;

EXCEPTION Error;

TYPE
  T = OBJECT
  METHODS
    enumerateFiles(enumProc: EnumProc) RAISES {Error};
    enumerateImports(enumProc: EnumProc) RAISES {Error};
    enumerateExports(enumProc: EnumProc) RAISES {Error};
    getLastError(): TEXT RAISES {}
  END;

  EnumProc = PROCEDURE(name: TEXT): BOOLEAN RAISES {};

PROCEDURE Create(name: TEXT; writeError: BOOLEAN := FALSE): T RAISES
{Error};

END A.

A trivial client looks like this:

MODULE ta EXPORTS Main;
IMPORT A;

VAR
  a := A.T;

PROCEDURE ListEntries(name: TEXT): BOOLEAN RAISES {} =
BEGIN
  RETURN TRUE
END ListEntries;

BEGIN
    a := A.Create(name := "libsupport.a", writeError := TRUE);
    a.enumerateFiles(ListEntries)
END ta.

The SRC compiler complains about the invocation of
a.enumerateFiles(ListEntries) as follows:

m3 -c ta.m3
"ta.m3", line 15: unknown qualification '.' (enumerateFiles)
"ta.m3", line 15: attempting to call a non-procedure
2 errors encountered

This appears to contradict part of the next to last paragraph on page 31
of the revised report which reads:

> If o is an object, ...  If m is one of o's methods, an invocation of the
> form o.m( ... ) denotes an execution of o's m method (Section 3).  Such
invocations are the only way to access methods.

Have I misunderstood the report or is this a bug in the SRC compiler.

A stripped down implementation of the interface A is attached.  I'd
appreciate suggestions about better ways to do the job.

Dick

MODULE A;

TYPE
  MyT = T OBJECT
    fileName: TEXT := NIL;
    lastErrorMessage := "No unreported errors."
  METHODS
  END;

PROCEDURE Create(name: TEXT; writeError: BOOLEAN := FALSE): T RAISES
{Error} =

BEGIN
  RETURN NEW(MyT, fileName := name, enumerateFiles := EnumerateFiles,
enumerateImports := EnumerateImports, enumerateExports :=
EnumerateExports, getLastError := GetLastError)
END Create;

PROCEDURE EnumerateFiles(t: MyT; enumProc: EnumProc) RAISES {Error} =

(* Calls enumProc for each file that is included in t.  The enumeration
terminates when enumProc returns FALSE or when the names of all files in
t have been passed to enumProc.  *)

BEGIN
  RAISE Error
END EnumerateFiles;

PROCEDURE EnumerateImports(t: MyT; enumProc: EnumProc) RAISES {Error} =

(* Calls enumProc for each symbol that is exported by a file in t.  The
enumeration terminates when enumProc returns FALSE or when the names of
all imports have been passed to enumProc.  *)

BEGIN
  RAISE Error;
END EnumerateImports;

PROCEDURE EnumerateExports(t: MyT; enumProc: EnumProc) RAISES {Error} =

(* Calls enumProc for each symbol that is imported by a file in t.  The
operation terminates when enumProc returns FALSE or when all of the
exports have been passed to enumProc.  *)

BEGIN
  RAISE Error
END EnumerateExports;

PROCEDURE GetLastError(t: MyT): TEXT RAISES {} =

(* Returns the most recent error message for the archive file.  The
message includes the name of the file and is in standard *IX format.  *)

BEGIN
  RAISE Error
END GetLastError;

BEGIN
END A.


------------------------------------------------------------------------------
Date:    21 Sep 1990 1142-PDT (Friday)
From:    <kalsow@src.dec.com>
Subject: Re: Compiler Bug for Objects?

The compiler behaves as you described and there is a compiler
bug, but it's not what you thought...

Your main program is buggy.  It declares a variable named 'a' and 
initializes it to A.T.  But, A.T is a type! The compiler should have 
complained about the variable declaration and all of its uses.

Changing "VAR a := A.T" to "VAR a: A.T" fixes your problem.


 - Bill Kalsow


------------------------------------------------------------------------------
Date:    Fri, 21 Sep 90 21:12:50 MET DST
From:    Thomas Roemke <modula-3@pbinfo.uni-paderborn.de>
Subject: Re: Compiler Bug for Objects




Hallo Dick,

sorry, but first of all your program is buggy !

>MODULE ta EXPORTS Main;
>IMPORT A;
>
>VAR
>	a := A.T;
>[..]
>

	VAR a := A.T is not a legal declaration.
	(which of course should be detected by the compiler)

	'a' has not type A.T and thus the qualifications are not allowed.

	In fact A.T is a type expression and not assignable to any variable at 
all. 
	Since type expressions are allowed in some contexts (i.e. TYPECODE(),NA
RROW(),..)
	there may be an internal type for type expressions and 'a' may have tha
t type.
  

	Try out VAR a: A.T; and your program will probably work.


Thomas

-- 
(*	Thomas Roemke, University Paderborn, FRG
	modula-3@uni-paderborn.de
	..!uunet!mcsun!unido!pbinfo!modula-3	*)

------------------------------------------------------------------------------
Date:    21 Sep 1990 1427-PDT (Friday)
From:    <mjordan@src.dec.com>
Subject: Re: Compiler Bug for Objects?


This was apparently lost when I posted it this morning...

Many a slip...

VAR
  a := A.T;

So what is the type of 'a'?  I get an "invalid use of type"  error from
my (the Olivetti) compiler on this line. Clearly the SRC compiler is
missing an error message. No doubt you meant:

VAR
  a: A.T := Create(name := "libsupport.a", writeError := TRUE);

On the implementation of 'A'.  I would first make A.T opaque and use:

TYPE
  T_public = OBJECT
  METHODS
    enumerateFiles(enumProc: EnumProc) RAISES {Error};
    enumerateImports(enumProc: EnumProc) RAISES {Error};
    enumerateExports(enumProc: EnumProc) RAISES {Error};
    getLastError(): TEXT RAISES {}
  END;

  T <: T_public;

and then in the implementation do

REVEAL T = T_public OBJECT
    fileName: TEXT := NIL;
    lastErrorMessage := "No unreported errors."
  METHODS
  END;

One day the clamour for some syntactic sugar for this frequently occurring
construct might reach our ears.

Mick



------------------------------------------------------------------------------
Date:    Tue, 25 Sep 90 17:53:41 -0500 (CDT)
From:    Paul Gunsch <gunsch@rchland.ibm.com>
Subject: fixes for RT/IBM 4.3

Forwarding note for Michael Bauers:
---------- Forwarded message begins here ----------

 There are a few problems when building SRC Modula-3, Version 1.5 on
IBM/4.3.  These problems are:

dist-1.5/system/runtime/M3machine.h.IBMRT
     Because '_packed' is a reserved word on the High C compiler we
needed to redefine it.
dist-1.5/system/runtime/M3Runtime.c
   'vfprintf' isn't in our library so I used fprintf instead.
dist-1.5/system/loader/m3ld.c
   I needed to write 'tempnam' for the IBMRT architecture.
dist-1.5/util/clone.c
   Fixed a syntax error in a '#if defined(IBMRT)' clause.
dist-1.5/util/merge.c
   'vfprintf' isn't in our library so I used fprintf instead.
dist-1.5/makefile
   Defined IBMRT on the CC command line, so that clone will compile
correctly.

I'm providing corrections of these problems as a small number of files
and a shell script.  All of the files are in a uuencoded compressed tar
file which is attached to this note.  Here are the instructions for
applying the corrections:

(1)	Save this message in a file, say changes.uu, in the directory that
contains dist-1.5, that is, the directory in which you extracted
m3-1.5.tar.Z from gatekeeper.

(2)	Execute the following commands:

        uudecode changes.uu
        zcat 1.5changes.IBMRT.tar.Z | tar xvf -

	At this point, you are ready to apply the changes.  If a file is
changed by the update procedure, the original file is saved with the
additional suffix .SRC

(3)	Apply the changes by executing the command

        applypatches

(4)     If the build is done using the clone directory setup as
specified in the SRC 1.5 build documentation, I have provided a shell
script to remove a few uneeded files that the clone process created.
Make sure you are in the top level build directory and then type
'rmuneeded'.

(5)     Once the build is done and working, the files that were untar'd
and the 1.5changes.IBMRT.tar file can be removed.

Michael J. Bauers, BSI
begin 666 1.5changes.IBMRT.tar.Z
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
+1,ZSGO?,YS[[6:]*
`
end

------------------------------------------------------------------------------
Date:    Thu, 27 Sep 90 11:52:35 PDT
From:    chased@Eng.Sun.COM (David Chase)
Subject: Anonymous enum types

I'd propose to leave it alone, and let the compiler issue a
gentle warning that perhaps you hadn't written what you had
meant to write.  This is easier than introducing TYPEOF, or
extending FIRST/LAST beyond their current use.

In the Olivetti compiler we had a "gentle warning" in the same vein for

  VAR x := NIL; (* Omitted type gives x a default type of NULL *)
  ...
  x := something with non-NULL type, requiring a run-time check;

This almost always indicated an error, though it is always possible
that such code is intended.  And yes, this occurred at least once in
real code as a mistake.  (I think we placed the error at the location
of the conversion, rather than at the declaration, which is
non-optimal, but better than a poke in the eye.)

David Chase (now at Sun)

