======================================================================== 1 ===
Date:    Sun, 2 Feb 92 19:36:59 PST
From:    muller@src.dec.com (Eric Muller)
Subject: archive of comp.lang.modula3 for January 1992

The archive of the messages sent to comp.lang.modula3 in January 1992
is now available in:

	gatekeeper.dec.com:pub/DEC/Modula-3/comp.lang.modula3/92-01.Z

Achives for the previous months are available in the same directory.

Eric.


======================================================================== 2 ===
Date:    Tue, 4 Feb 1992 15:34:37 PST
From:    David Goldberg <goldberg@parc.xerox.com>
Subject: M3 tags package for GNU Emacs

I have put the tags package we use at PARC on parcftp@xerox.com, in
/pub/goldberg/tags.tar.Z.   Its available using anonymous ftp.
Here's the README file from tags.tar:

================

This is a tags package for Modula-3 and GNU emacs.  It consists of a
'tags' program that prints a tags file on stdout, and an improved
version of tags.el.  See the comments in tags.el and tags.c for more
info.

As an example of how to use these programs, you might create a tags
file via these commands (where INSTALL_PREFIX is the location of the
installed Modula-3)

   cd INSTALL_PREFIX
   tags -q include/m3/*.i{3,g} > INSTALL_PREFIX/FTAGS

and invoke the tags package with these lines in your .emacs file:

   (load-file "tags.el")
   (visit-tags-table "INSTALL_PREFIX/FTAGS")


David Goldberg  goldberg@parc.xerox.com
Marvin Theimer  theimer@parc.xerox.com



======================================================================== 3 ===
Date:    4 Feb 92 21:48:38 GMT
From:    do12+@andrew.cmu.edu (Dick Orgass)
Subject: Beta build of SRC Modula-3 2.01 for RISC/6000 Available

A quite usable but not completely shaken down build of SRC Modula-3 2.01
and all of the released libraries is available for anonymous ftp from
emsworth.andrew.cmu.edu [128.2.30.62] as file m3/binary.IBMR2-1.01.tar.Z.

I'd appreciate it if others would try the build and let me know about
problems that are found so there is a chance of fixing them before the
final release from SRC.

This build is done under the assumption that it is installed in
/u/decsrc.  If you install it in another place, just add a symbolic link
from /u/decsrc to that place.  Alternatively, you could rebuild the
driver.

Comments about this build:

        (1)     The system has passed the ptests and etests.

        (2)     I haven't run the Pkl test programs yet and they caused
        some problems with 1.6.

        (3)     The trestle demo BadBricks stops with an invalid
        instruction (sigh!).

        (4)     The libraries are built as ordinary libraries -- I
        haven't modified the imake macros to make share libraries as was
        done form 1.6.

        (5)     The compiles were done without -O and with -g so the
        library files are very much bigger than they should be.

        (6)     There is a file, m3compiler.AIX386 in directory lib/m3
        which you can delete.  It's a cross compiler for AIX PS/2 that
        didn't help me solve a problem.

Dick


======================================================================== 4 ===
Date:    5 Feb 92 23:14:49 GMT
From:    d9mikael@dtek.chalmers.se (Mikael Wahlgren)
Subject: Re: Modula-3 fans, read comp.lang.modula-3! (Was: Re: Modula-3 for PC)

In article <1992Feb5.085953.2347@cs.rug.nl> laverman@cs.rug.nl (Bert Laverman) 
writes:

>Now as a repeat: The SRC-m3 compiler (current version ca. 2.01) is a
>C generating compiler for several _UNIX_ machines. The library with it
>supports several _UNIX_ variants and systems. _It_does_not_support_MSDOS_
>nor does it support the 80386 (the most likely processor for a first
>80x86 implementation)
>  If you have a PC compiler for m3, or know of somebody having one,
>NOTIFY US (the comp.lang.modula3 readers) IMMEDIATELY! We don't know
>of it.

Well, I have had thoughts on porting the SRC-m3 compiler to OS/2 2.0, but I
don't know if that counts (and if it is relevant).  It certainly runs on 
"PC's", but you can run Unix on PC's too...  Anyone interested in a Modula-3
port to OS/2 2.0 (32-bit operating system).  This is not a commitment to do
a port, just wanting to know if there is any interest...

Mikael Wahlgren      d9mikael@dtek.chalmers.se


======================================================================== 5 ===
Date:    6 Feb 92 22:33:56 GMT
From:    harbison@bert.pinecreek.com (Sam Harbison)
Subject: A UNIX shell in Modula-3

David Hanson and David Dobkin of Princeton University kindly gave me a
copy of their "small shell", a small UNIX shell written in C which
they use as an example program in some of their courses. I have finished
translating/rewriting it into Modula-3, and it is now available for 
anonymous ftp from bert.pinecreek.com as file pub/lib/m3shell-1.0.tar.Z.

It won't supplant the Korn shell, but it handles command execution,
I/O redirection, pipes, and background execution. For example:

	(cd /tmp; ls -lt | cat) >> thud &

It doesn't handle quotes or filename expansion. The program is
intended as an interesting example of how to hack UNIX tastefully in
Modula-3.  In giving it a Modula-3 flavor, I've split the single C
file into several modules, put in a couple of objects, and changed the
error handling scheme to use exceptions. The program includes an
interface and module named M3Unix, which provides a Modula-3 flavored
interface to several UNIX system calls (i.e., the ones I needed).
Enjoy.

Sam Harbison 
Pine Creek Software; Suite 300; 305 South Craig Street; Pittsburgh, PA 15213;
USA. Phone&FAX: +1 412 681 9811. E-mail: harbison@bert.pinecreek.com.


======================================================================== 6 ===
Date:    Thu, 6 Feb 92 21:57:46 PST
From:    muller@src.dec.com (Eric Muller)
Subject: SRC Modula-3 2.03 available

SRC Modula-3 2.03 is available from gatekeeper.dec.com in
pub/DEC/Modula-3/m3-2.0.

This version has been successfully installed on a DECstation and on a
VAX.  I believe that the SPARC version is ok, and probably the SUN3 as
well.  The status for the other machines is unknown.  

To get started, you need to fetch the archive
boot.<architecture>-2.03.tar.Z and libm3-2.03.tar.Z.  Because of the
reorganization for ports, you cannot really reuse a 2.01 installation.


Main changes since 2.01:

 - it should be easy to do ports of this version; well, the machinery
   to build a cross-compiler and to cross compile the driver and the
   compiler are there (you still have to modify the machine-specific
   code).  The bootstrap archives are now built using that mechanism.

 - David Goldberg provided the implementation of the floating point
   interfaces for SPARC.  Thanks a lot.

 - missing setjmp.o added for IBMR2 and AP3000

 - a number of bug fixes in the compiler.  

 - the driver in -make mode does the correct dependency analyzis for 
   generic interfaces and modules.

 - command line arguments for the runtime.  We have reserved command
   line arguments of the form @M3<something> for the runtime.  Before
   the user code starts, these arguments are removed from the list
   seen by the user code, and stored in a safe place.  The interface
   RTParams can be used to access them. <something> can be just a
   <name>, or of the form <name>=<value>.  Two such arguments are
   used today: @M3showthread and @M3showheap.

 - showthread: if a Modula-3 program is started with the runtime
   argument @M3showthread=<value>, this will fork a process and run
   the program <value> (or showthread if =<value> is missing) in that
   child process.  That program should close its stdout to allow the
   parent process to proceed and will then receive on stdin a sequence
   of thread scheduling events for the parent process.  The tools
   source archive contains the program showthread, that uses Trestle
   to display this scheduling activity.

 - showheap: if a Modula-3 program is linked with the ShowHeap
   interface (available in the tools source archive) and Trestle, and
   the @M3showheap runtime argument is given, this will open a Trestle
   window in which the status of the heap will be displayed.  There
   are also some buttons in that window to control the
   allocator/collector.  Note: the code to handle that window is in
   the process being examined, contrary to showthread which is in a
   separate process.  We are going to convert showheap to be in a
   separate process so that the Trestle activity does not interfer
   with the program, and you don't need to link differently.


-- 
Eric.



======================================================================== 7 ===
Date:    7 Feb 92 02:03:00 GMT
From:    v064qpfu@ubvmsb.cc.buffalo.edu (Christopher S. D'Arrigo)
Subject: MODULA2


This questions deal with Modula 2, I know the news group is based on Modula 3 
but since I couldnt find a Modula 2 News Group, I figured this was my best
shot....

I have JUST started using Modula 2 and was wondering...

How do you evaluate Exponents, if  Num^Power is a pointer to Power
and Num ** Power is an invalid operand, what is the correct way to
code for exponents...

Thanks!

*************************************************************************
* All Things Considered, I'd Rather Be Doing COBOL * My Opinions are my *
*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*  own so they must  *
* IN%"V064qpfu@UBVMS", IN%"cdarrigo@cs.Buffalo.edu"*   be right! -CED   *
*************************************************************************


======================================================================== 8 ===
Date:    7 Feb 92 05:46:47 GMT
From:    NU158739@NDSUVM1.BITNET (Shaun Wetzstein)
Subject: Re: Modula-3 fans, read comp.lang.modula-3! (Was: Re: Modula-3 for PC)

I would like to see Modula-3 for OS/2 v2.0!

Shaun Wetzstein nu158739@vm1.nodak.edu


======================================================================== 9 ===
Date:    Sat, 8 Feb 92 00:06:43 PST
From:    muller@src.dec.com (Eric Muller)
Subject: Re: patch for m3-2.03

In article <1992Feb7.235931.29769@src.dec.com>, I write:

> There is a little problem with the top level m3makefile of all the
> archives (this is actually the same file in all cases).

I forgot to mention that this problem and the fix have been found by
Man-Chi Pong, from The Hong Kong University of Science & Technology.
Thanks a lot !

-- 
Eric.



======================================================================== 10 ===
Date:    Fri, 7 Feb 92 23:59:31 PST
From:    muller@src.dec.com (Eric Muller)
Subject: patch for m3-2.03

There is a little problem with the top level m3makefile of all the
archives (this is actually the same file in all cases).  Below is the
difference between the old and the new version.  This modification is
necessary for SPARC (at least).

*** m3makefile.old	Fri Feb  7 23:52:18 1992
--- m3makefile	Fri Feb  7 23:53:15 1992
***************
*** 145,146 ****
--- 145,147 ----
  #define machine_iter(x)                                                     @
@\
+ all_##x::                                                                   @
@\
  	@for d in $(MACHINES); do \                                         @@\
***************
*** 149,158 ****
  
! all_cross::
! 	machine_iter (cross)
! all_bootstrap_both::
! 	machine_iter (bootstrap_both)
! all_bootstrap_scratch::
! 	machine_iter (bootstrap_scratch)
! all_pack::
! 	machine_iter (pack)
  
--- 150,155 ----
  
! machine_iter (cross)
! machine_iter (bootstrap_both)
! machine_iter (bootstrap_scratch)
! machine_iter (pack)
  


-- 
Eric.



======================================================================== 11 ===
Date:    7 Feb 92 01:23:59 GMT
From:    torki@doitcr.doit.sub.org (Torsten Kirschner)
Subject: Q: Does M3 version 2.X exist/work on DECstation 5000/200 ?

Dear M3 - group,

I have not been following the M3 version 2.x postings, but as I read
about IBM RS/6000 ports I ask You whether the implementation for
the DECstation 5000 series works ?
I assume the new version's tar.Z can be ftp'ed from gatekeeper.dec.com,
but I'd like to hear about Your experience, especially with the Trestle
Window System which is kind of troublesome with M3 1.6 (as Greg Nelson
himself said).
Thanks in advance for any hints & tips. (I use DS5000/200 w/Ultrix 4.2
and DECwindows 11R4, if that has anything to do with it.)

Torsten


======================================================================== 12 ===
Date:    8 Feb 92 15:41:34 GMT
From:    harbison@bert.pinecreek.com (Sam Harbison)
Subject: Modula-3 News #2 correction

In the article on Queen Mary & Westfield College in "Modula-3 News"
#2, I referred to Jean Dollimore as 'he'; it should have been 'she'.
My sincere apologies to Ms. Dollimore.

Sam Harbison 
Pine Creek Software; Suite 300; 305 South Craig Street; Pittsburgh, PA 15213;
USA. Phone&FAX: +1 412 681 9811. E-mail: harbison@bert.pinecreek.com.


======================================================================== 13 ===
Date:    Mon, 10 Feb 92 14:54:21 PST
From:    muller@src.dec.com (Eric Muller)
Subject: Re: Q: Does M3 version 2.X exist/work on DECstation 5000/200 ?

In article <1737@doitcr.doit.sub.org>, torki@doitcr.doit.sub.org (Torsten Kirsc
hner) writes:

> I have not been following the M3 version 2.x postings, but as I read
> about IBM RS/6000 ports I ask You whether the implementation for
> the DECstation 5000 series works ?

The quality of the various architecture is a consequence of:
  - the number of users of that architecture
  - the similarity of that architecture DS3100

DS3100 (i.e. DECstation running Ultrix 4.2) is the architecture on
which we develop.  We have a fair number of users at SRC.  It is
certainly the one that works the best.

VAX comes next, as we have one of those machines, and we try to test
it from time to time (we don't have many VAX users, so it may be
behind the DS3100 version).

We don't have any of the other architectures available to us, so we
have to rely on good willing people outside.  They are putting a fair
amount of work to make Modula-3 a reality, thanks to them all !
Sometime, their task is greatly complicated by differences between
their architecture and the DS3100 architecture that we did not
anticipate.  Sometime, they have a small number of users and it is
difficult to test thoroughly the system.  By all means, do not equate
quality of the port with quality of the people doing it. 

-- 
Eric.



======================================================================== 14 ===
Date:    Wed, 12 Feb 92 17:51:36 HKT
From:    mcpong%uxmail.ust.hk@YALEVM.YCC.Yale.Edu
Subject: Trestle scrollbar?

Is there any MODULE scrollbarVBT available in Trestle?
Any pre-release version is better than nothing.
Thanks

mcpong@uxmail.ust.hk
Man-Chi Pong
The Hong Kong University of Science & Technology


======================================================================== 15 ===
Date:    Wed, 12 Feb 1992 11:08:53 PST
From:    David Nichols <nichols@parc.xerox.com>
Subject: pragma question

The SRC implementation restricts the appearance of certain pragmas, e.g.
it is an error for <*UNUSED*>  to appear other than just before a
declaration.  But the green book, on page 62, states "Pragmas are hints
to the implementation; they do not affect the language semantics."  It
seems to me that refusing to compile an otherwise correct program is
affecting the language semantics.  What if GNU M3 decides to give a
different meaning to <*UNUSED*>, or requires a different placement? 
Then I wouldn't be able to write code that uses <*UNUSED*> and is
portable between the two compilers.

	David


======================================================================== 16 ===
Date:    12 Feb 92 18:10:21 GMT
From:    cs224054@cs.brown.edu (Manojit Sarbar)
Subject: Re: Trestle scrollbar?

In article <9202120951.AA13394@ustsu1.ust.hk.ust.hk1> mcpong%uxmail.ust.hk@YALE
VM.YCC.Yale.Edu writes:
>Is there any MODULE scrollbarVBT available in Trestle?

I did some programming with Trestle. There is no ScrollarVBT
so far as I know, I had to write my own.

-manojit


======================================================================== 17 ===
Date:    Wed, 12 Feb 92 09:57:59 PST
From:    <mhb@src.dec.com>
Subject: Re: Trestle scrollbar?


We at SRC have developed a large collection of UI components. We 
are using them in a handful of heavily-used applications, so they 
are pretty solid --- by no means "vaporwear". We are currently working 
on the reference manual, as well as some tweaking, tuning, enhancing, 
and plain ol' fashion debugging. 

To give you a feel for the types of widgets that will soon be available 
in Trestle, here's a list of the primary VBT classes:

        BooleanVBT     ChoiceVBT       FileBrowserVBT  FlexVBT
        GuardedBtnVBT  NumericVBT      PixmapVBT       ReactivityVBT
        ScrollerVBT    ShadowedBarVBT  ShadowedVBT     SourceVBT
        SplitterVBT    TextBrowserVBT  TextEditVBT     TrillBtnVBT
        TypescriptVBT  ViewportVBT     ZChassisVBT

Hopefully, the names will give a clue as to the functionality you
can expect.

Marc

PS. The components are the building blocks of a GUI system called 
FormsVBT.  As posted to this newsgroup in December, we have a "mini" 
version of that system mostly running in Modula-3, but it's a few 
months before FormsVBT will be ready for distribution. Stay tuned....


======================================================================== 18 ===
Date:    13 Feb 92 14:54:37 GMT
From:    moss@cs.umass.edu (Eliot Moss)
Subject: Re: pragma question

I tend to agree that the whole area of pragmas needs work. How can I as a
compiler writer choose a pargma name guaranteed not to conflict with any other
compiler's? I also suspect that it would be best to require (suppressable)
warning for unrecognized/misplaced pragmas, so a programmer at least knows
that a compiler did not process the pragma. And saying that a pragma may not
affect semantics may be too limiting; not to mention the effect you noticed: a
pragma affecting the acceptance/rejection of a program by the compiler. (One
could argue that this does *not* affect semantics, since the semantics of an
unaccepted program are not defined.) We haven't implemented any pragmas for
gm3 yet, but I'm sure there will be a day ....			Eliot
--

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


======================================================================== 19 ===
Date:    13 Feb 92 09:16:35
From:    dagenais@vlsi.polymtl.ca (Michel Dagenais)
Subject: Re: Trestle

In article <9202121758.AA20698@jumbo.pa.dec.com> mhb (Marc H. Brown) writes:

>   To give you a feel for the types of widgets that will soon be available 
>   in Trestle, here's a list of the primary VBT classes:
>
>	   BooleanVBT     ChoiceVBT       FileBrowserVBT  FlexVBT
>	   GuardedBtnVBT  NumericVBT      PixmapVBT       ReactivityVBT
>	   ScrollerVBT    ShadowedBarVBT  ShadowedVBT     SourceVBT
>	   SplitterVBT    TextBrowserVBT  TextEditVBT     TrillBtnVBT
>	   TypescriptVBT  ViewportVBT     ZChassisVBT
>

Humm... hard to survey what is there and what is not when things are moving
at this pace. Not that i will complain for all the good stuff coming out!

Here is a more basic question about the architecture of Trestle. In
InterViews (a C++ windowing toolkit) Glyphs (read VBT) are "shared"
objects. Thus, a Glyph that gets used by numerous other composite Glyphs,
mapped to a number of windows, will need to keep information about all these
contexts (for each context remember the glue settings and so on). This
contextual information can be kept in a hash table and the calling path,
which determines the exact context, can serve as the key. Therefore, the
Glyphs can represent directly complex objects (drawings or documents) with
multiple viewers.

In Trestle, from what i could gather in the comments sread around the
files, the VBTs are not shared. Therefore, there is a one to one
correspondance between the display and the VBTs. Thus they act as display
lists. If one wants to implement a diagram or document editor, he then needs to
create new VBTs for each instance of a component (NAND gate for example)
in each viewer. When this component is modified, each VBT instance
representing it must receive an update message and react accordingly.

Am i correct? In which area do you feel that Trestle needs more
functionality? Do you know enough about InterViews to comment on what exists
in it and doesnt in Trestle, and vice-versa?
--
---------------------------------------------------------------------

Prof. Michel Dagenais			    dagenais@vlsi.polymtl.ca
Dept of Electrical and Computer Eng.
Ecole Polytechnique de Montreal		    tel: (514) 340-4029

---------------------------------------------------------------------


======================================================================== 20 ===
Date:    13 Feb 92 22:46:35 GMT
From:    n8243274@henson.cc.wwu.edu (steven l. odegard)
Subject: Re: pragma question


May I recommend packaging pragmas much like modules are packaged now.  Thus
if a particular pragma set is used, ie. for formal verification, then the
same is imported in a like manner.

I am working on some extended pragma names for documenting incremental
extension.  I don't look forward to having to select names other than the
intuitive set I use.

By the way, in each case, the form is <* KEYWORD other stuff *>, where
_other stuff_ is handled by KEYWORD.  The position of where the pragma
appears is also significant, in some cases.


======================================================================== 21 ===
Date:    13 Feb 92 21:54:21 GMT
From:    emery@Dr_No.mitre.org (David Emery)
Subject: Re: pragma question

Eliot writes:
>How can I as a compiler writer choose a pargma name guaranteed not to
>conflict with any other compiler's? 

I'd suggest that DEC, or whoever maintains the Modula-3 Reference
Manual, could maintain a 'registry' of pragma names and meanings.  In
the Ada community, there are two ISO WG9 groups that deal with this.
The ARG handles questions of conformance to the standard, such as "Can
I add an extra parameter to this pragma?".  The URG handles uniformity
issues.  One URG issue deals with pragma INTERFACE_NAME, which in Ada
terms associates an external object (or subprogram) denoted by pragma
INTERFACE with its external (i.e. linker) name.  

Other URG issues deal with things like the "normal" size of INTEGER,
and similar issues that are not legality issues, but are important for
portability.  Modula-3 could probably use a similar group, to catalog
these issues, if not decide them.

					dave


======================================================================== 22 ===
Date:    Thu, 13 Feb 92 20:02:11 GMT
From:    torki@doitcr.doit.sub.org (Torsten Kirschner)
Subject: Re: Q: Does M3 version 2.X exist/work on DECstation 5000/200 ?

In article <1992Feb10.145421.6112@src.dec.com> you write:
} In article <1737@doitcr.doit.sub.org>, torki@doitcr.doit.sub.org (Torsten Kir
schner) writes:
} 
} > I have not been following the M3 version 2.x postings, but as I read
} > about IBM RS/6000 ports I ask You whether the implementation for
} > the DECstation 5000 series works ?
} 
} The quality of the various architecture is a consequence of:
}   - the number of users of that architecture
}   - the similarity of that architecture DS3100
} 
} DS3100 (i.e. DECstation running Ultrix 4.2) is the architecture on
} which we develop.  We have a fair number of users at SRC.  It is
} certainly the one that works the best.
} 
} VAX comes next, as we have one of those machines, and we try to test
} it from time to time (we don't have many VAX users, so it may be
} behind the DS3100 version).
} 
} We don't have any of the other architectures available to us, so we
} have to rely on good willing people outside.  They are putting a fair
} amount of work to make Modula-3 a reality, thanks to them all !
} Sometime, their task is greatly complicated by differences between
} their architecture and the DS3100 architecture that we did not
} anticipate.  Sometime, they have a small number of users and it is
} difficult to test thoroughly the system.  By all means, do not equate
} quality of the port with quality of the people doing it. 
} 
} -- 
} Eric.


Dear Eric,

thank You for Your quick and well sufficient response to my inquiry.
As a matter of fact one has to thank the good poeple at SRC for their
work. I am using M3 1.6 with Greg Nelson's Trestle system.
All I can say quickly is that I am truly impressed by M3 and prefer
it to any other language available on my system.
Due to Your information I will ftp the latest version of M3 from
gatekeeper.dec.com. I think it is 2.03 by now, but never mind to correct
me if it's 2.04 already.

Not that it was of any interest to You, but my reason for posting the
questions about M3 2.x on DECstations was that ftp-ing for me as a
X.400 user is complicated. In addition to that bandwidth to the USA is
limited and I have not found a mirror of gatekeeper as far as M3 is
concerned. No European ftp server seems to have M3 versions >1.6.

I would be glad and thankful if You and everybody involved with Modula 3
kept on their precious work. I am looking forward to a time when I can
contribute something, even if it was just a little hint about the dis-
tribution.

Thanks again
Torsten
--
Torsten R. Kirschner    Tel. (+49 89) 3234102    BITNET: torki@dm0mpf11
SMTP : torki@doitcr.doit.sub.org           torki@mpipf-muenchen.mpg.dbp.de
X.400: /C=de/ADMD=dbp/PRMD=mpg/O=mpipf-muenchen/S=torki



======================================================================== 23 ===
Date:    14 Feb 92 15:05:18 GMT
From:    harbison@bert.pinecreek.com (Sam Harbison)
Subject: bert.pinecreek.com anon FTP down

Until further notice, anonymous ftp to bert.pinecreek.com is
unavailble. It will likely be down for weeks or months.  The file
system holding that account became corrupted last night, and I don't
have a readily available backup.

This happened while building a Modula-3 cross compiler on that disk.
Hmmm, could it be...?  Nah...

Sam Harbison 
Pine Creek Software; Suite 300; 305 South Craig Street; Pittsburgh, PA 15213;
USA. Phone&FAX: +1 412 681 9811. E-mail: harbison@bert.pinecreek.com.


======================================================================== 24 ===
Date:    15 Feb 92 16:50:23 GMT
From:    n8243274@henson.cc.wwu.edu (steven l. odegard)
Subject: bug in m3-2.03: procedure declaration within a block

Should every error found on the Beta Test be reported here?



MODULE Bug EXPORTS Main ;
  (* Demonstrate that if a I declare a procedure in a declaration within a
	block, then compiler will produces a C syntax error.
	Here I declared such a procedure _FinalFive_. *)

IMPORT Wr, Fmt, Stdio ;

TYPE funny = ARRAY[ 1 .. 5 ] OF INTEGER ;
PROCEDURE FunnyFive( f : funny ) = (* This procedure causes no error. *)
  BEGIN
    FOR k := 1 TO 5 DO
	Wr.PutText( Stdio.stdout,
		"f[" & Fmt.Int( k ) & "] = " & Fmt.Int( f[k] ) & " " ) ;
    END (* OF FOR k *) ;  Wr.PutText( Stdio.stdout, "\n" ) ;
    Wr.Flush( Stdio.stdout ) ;
END FunnyFive ;

BEGIN

(* ---
   FunnyFive( funny{ 5, 4, 3, 2, 1 } ) ;
   FunnyFive( funny{ -1, .. } ) ;
--- *)

  TYPE final = ARRAY[ 1 .. 5 ] OF INTEGER ;
  PROCEDURE FinalFive( f : final ) = (* This procedure causes a C error. *)
    BEGIN
      FOR k := 1 TO 5 DO
	Wr.PutText( Stdio.stdout,
		"f[" & Fmt.Int( k ) & "] = " & Fmt.Int( f[ k ] ) & " " ) ;

      END (* OF FOR k *) ;  Wr.PutText( Stdio.stdout, "\n" ) ;
      Wr.Flush( Stdio.stdout ) ;
  END FinalFive ;
  BEGIN (* scope for _FinalFive_ 'test' procedure with _final_ type. *)
    FinalFive( final{ 5, 4, 3, 2, 1 } ) ;
    FinalFive( final{ -1, .. } ) ;
  END (* OF BEGIN (* scope for _FinalFive_ *) *) ;

(* Output should be: ---
f[1] = 5 f[2] = 4 f[3] = 3 f[4] = 2 f[5] = 1 
f[1] = -1 f[2] = -1 f[3] = -1 f[4] = -1 f[5] = -1 
--- *)
END Bug.


(* ---
g> m3 bug.m3
ccom: Error: bug_m.c, line 39: syntax error
              void 1__FinalFive ();
      -------------^
ccom: Error: bug.m3, line 26: syntax error
               void 1__FinalFive (f) _t91633b98 f; { _RAISES_NONE_HANDLER _h6;
      --------------^
ccom: Error: bug.m3, line 26: syntax error
        {   _h6.next = *((_TRY_HANDLER **) &_M3__handlers);   _M3__handlers = 0
; };
      --^
ccom: Error: bug.m3, line 26: redeclaration of _h6
	.
	 .
	  .
(* You may generate the other 30 or so errors at your leisure. *)
--- *)


======================================================================== 25 ===
Date:    Mon, 17 Feb 1992 23:58:14 GMT
From:    sharon@lcs.mit.edu (Sharon Perl)
Subject: the Fmt interface

Is there a particularly good reason why Fmt.FN should result in a checked
runtime error when the number of format specifiers in the format string is not
equal to the number of supplied texts? I'd prefer that it raised an exception
that could be caught by the caller. I wanted to use Fmt.FN in writing a simple
expression interpreter. The user of the interpreter provides a format string
and a list of expressions to be evaluated (by the interpreter) to produce the
texts for the format string.  I'd like to pass the format string supplied by
the user directly to Fmt.FN along with the array of texts resulting from
evaluating the expressions, without having to first parse the format string
myself to check whether the number of texts is correct.  I'd like to just catch
an exception from Fmt.FN and provide a sensible error message for the user when
the format string is incorrect.

In general, it seems to me that checked runtime errors should only result from
errors that are most definitely programming errors, and for which the only
thing the caller could possibly do in catching an exception is print an error
message and terminate the program.  With Fmt.FN this is not the case.

Note that the <* FATAL *> pragma makes it easy to instruct the compiler that
particular errors should in effect be checked runtime errors, but there's no
way to reverse the situation and "catch" a checked runtime error.

Sharon Perl
MIT Lab for Computer Science
sharon@lcs.mit.edu


======================================================================== 26 ===
Date:    18 Feb 92 18:30:19 GMT
From:    sharon@lcs.mit.edu (Sharon Perl)
Subject: Re: the Fmt interface

Sam Harbison writes:

  Yeah! Yeah! (thumping table) *All* checked run-time errors should be
  mapped to exceptions. I don't want some guys in Palo Alto deciding what's
  fatal to MY program!

  (A more reasoned argument is available upon request.)

Actually, CLU did this and it seems to work just fine. CLU has a special
exception called "failure" which has a single text argument.  All routines can
raise "failure" in addition to any explictly listed exceptions in their
interfaces.  An unhandled exception in a routine is converted to "failure". So,
for example, an array bounds error causes the "bounds" exception to be raised.
If the caller of the array operation does not catch "bounds", the result is
that the caller raises "failure". But "failure" can be caught with an exception
handler just like any other exception.

I haven't thought this through, but it seems that something like this could
work in Modula-3. It might be different than CLU's mechanism since M3 doesn't
have the uniformity that CLU does in its treatment of operations on built-in
types compared with user-defined procedures. Is there a reason why this
wouldn't work?

Sharon Perl
MIT Lab for Computer Science
sharon@lcs.mit.edu


======================================================================== 27 ===
Date:    19 Feb 92 17:33:08 GMT
From:    moss@cs.umass.edu (Eliot Moss)
Subject: Re: the Fmt interface

No, I see no reason why mapping checked run-time errors to exceptions won't
work. It is, however, more difficult to implement since some checked run-time
exceptions are turned into Unix signals and it is much easier to print a
message and abort than fiddle with the running state so that returning from
the signal handler will work as desired. And it's probably hard to do in a
single portable way, too. Finally, if signal handlers are used, they do not
always allow the handler to distinguish the reason for the signal as well as
one would like, especially if it has to do with various numeric problems.
Still, I tend to support the idea. Are there other compelling reasons for the
the design's being the way it is?
--

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


======================================================================== 28 ===
Date:    19 Feb 92 12:49:25 GMT
From:    qs101@cl.cam.ac.uk (Quentin Stafford-Fraser)
Subject: Problems installing for HPUX

I have been trying to build m3 v2.03 for HP-UX 7.0.

The various makefiles etc took quite some tweaking, but I eventually got
an 'm3' binary after 'm3make build_boot install_boot'

Unfortunately, any attempt to use this produces:

unrecognized option '-z4'
usage: m3 [-?] [options] [-o pgm|-a lib|-c]     sources... objs... libs...

Fatal Error: bad usage

   Can anybody help ? Please?


 ------------------------------------------------------------------------
 Quentin Stafford-Fraser                   "I've no idea what my employer
 Cambridge University Computer Lab          thinks about this."
 qs101@cl.cam.ac.uk
 Tel +44 223 334645
 ------------------------------------------------------------------------


======================================================================== 29 ===
Date:    19 Feb 92 13:15:38
From:    dagenais@vlsi.polymtl.ca (Michel Dagenais)
Subject: Compiling Trestle demo applications

I have not been able to find a README that explains how to build and
install the programs in the directory modula3-SRC-2.03/trestle/apps. The 
"m3make build_trestle install_trestle" command does not build these sample
trestle applications. I tried "cd trestle/apps; m3make all install" but
this did not get very far on my SparcStation 1. Before i go and compose 
a suitable m3makefile for this directory, is there something i have 
overlooked? The rest of the build/install for SRC 2.03 just went fine.

By the way, if there is enough interest i could put up for ftp the sparc
binaries for Modula 3 SRC 2.03... send e-mail if this is all you need to
start using Modula 3 :-).
--
---------------------------------------------------------------------

Prof. Michel Dagenais			    dagenais@vlsi.polymtl.ca
Dept of Electrical and Computer Eng.
Ecole Polytechnique de Montreal		    tel: (514) 340-4029

---------------------------------------------------------------------


======================================================================== 30 ===
Date:    Thu, 20 Feb 92 07:11:54 PST
From:    msm@src.dec.com (Mark S. Manasse)
Subject: Re: Compiling Trestle demo applications

The apps subdirectory of trestle is supposed to build some test programs,
and not install any of them.  Other than BadBricks, I don't think that
anything it builds is terribly useful, except to test that Trestle and M3
are working, and as examples of how to write simple Trestle programs.

Mark


======================================================================== 31 ===
Date:    Thu, 20 Feb 92 15:49:59 PST
From:    <swart@src.dec.com>
Subject: Re: the Fmt interface


There are two different issues running through this discussion
and I think they must discussed separately.

The first is a style question brought up by Sam Harbison:  What should
the result of a procedure be when it has been called incorrectly by
a client.  Should it raise a specific exception, signal a runtime
error, or return an erroneous answer?  Note that the Larch/Modula3
(LM3) specification language is capable of specifying any combination
of these behaviors.

In general returning erroneous answers is not great, especially when
the requirements that the client is expected to meet are difficult
for the client to verify.  But sometimes the performance cost of
verifying the condition is so great that one wants to avoid the
checking.  The locking level requirements of Trestle and of the Thread
interface are good examples.  Note that a given implementation might
generate a checked runtime error even if the specification allows
erroneous results.  For example, Thread.Release in M3 generates a checked
runtime error if it is called by the thread that is not holding the
mutex even though the specification allows chaos.

What about raising a separate exception for each thing a client could
do wrong?

On one extreme, consider a client that passed in NIL to a procedure
that needs a non-NIL object.  Should there be a special exception listed
in the RAISES clause for this?  I've seen some procedures in Modula
2+ with 15 exceptions on the RAISES clause!  I don't like using
procedures like that.

On the other hand, the client could pass in a noninvertible matrix
into a matrix invert routine.  An exception or return code, would
be much nicer than a checked runtime error, even if there was a separate
CheckInvertible routine.

In the end the decision of how errors should be reported depends on
the abstraction designers and their model of what clients want.  I don't
believe there can be a general rule.  If the designers of your favorite
interfaces get it wrong, tell them!  Of course, if too many clients
get into the act you end up with a mess of too many options and
exceptions and nobody is happy.

The second issue is whether all checked runtime errors should be turned
into special exceptions (with standard names or not) that may be caught
explicitly or by the ELSE clause of a TRY EXCEPT.  We actually did
this to our Modula 2+ system:

  - The only place where we took advantage of it was in the Tinylisp,
    (a Lisp/Modula 2+ hybrid) debugger.  This debugger lived inside
    your Modula 2+ program and would take control if one of the threads
    got a checked runtime error.  It could then display the stack,
    examine variables and destroy or restart the thread.  It was
    necessarily in bed with the exception machinery and the the runtime
    architecture.

  - We didn't do it much, but if one did want to simply mask bugs by
    using TRY EXCEPT ELSE one would at least want to log a stack trace
    or the exception name somewhere.  I would argue that since TRY
    EXCEPT ELSE is not currently defined to catch runtime errors and
    has no place to get a parameter, that if we do decide to implement
    runtime errors as exceptions that we invent a new Failure exception
    that could be caught.  The argument to Failure would hopefully be
    a TEXT containing something suitable for logging.

  - Masking programming bugs has a way of turning a fail-stop program
    into a byzantine one.  Fail stop programs are much easier to deal
    with.  I'm not sure I would want my program to continue after a
    bug without my having determined what went wrong.  This was one
    reason why programmers did not knowingly use TRY EXCEPT ELSE to
    catch errors.  (They sometimes did so unknowingly when feeling lazy
    when dealing with procedures that raise 15 different exceptions.)

  - It takes more mechanism to report an error.  For example, a Unix
    signal comes in and has to be directed into the right thread and
    that thread has to be made to execute the proper exception handling
    code.  We had cases where bugs have messed up the exception
    delivery machinery and errors have gotten disguised.

Garret Swart


======================================================================== 32 ===
Date:    Thu, 20 Feb 92 13:38:41 PST
From:    <swart@src.dec.com>
Subject: Safe cheap objects for Modula 3


This message outlines an idea to allow the compiler to allocate certain
objects on the stack and/or combine several objects and allocate them
as one unit, saving allocator and garbage collection overhead.  This
technique allows us to gain the advantages of C++'s stack resident
objects without any of the inherent unsafety that they have in C++.

The idea is to introduce a new pragma that gives the compiler more
information about object lifetimes and thus allows it to allocate
objects more efficiently.

First we introduce a new parameter passing mode, called USE, a
restriction of Modula 3's default "value" mode, for use on REF and OBJECT
types.  A value passed by USE can only be narrowed, have its fields
accessed, be dereferenced (if it is a REF type) or be passed as a USE
mode parameter.  It is thus impossible for a recipient of a USE mode
parameter to retain a handle to the object after its return.  USE can
be the passing mode for "self" in object methods, however as the
Modula-3 object syntax does not mention "self" in the method signature
we use the convention that <*USE*> after the method name but before
the parameter list refers to the passing mode of "self".

With the extra information provided by USE, it would then be the
compilers option to note that NEW was called in a context where the
result was only used as a USE mode parameter and allocate the object
on the stack.  For example given Goo.T

  INTERFACE Goo;
  TYPE T <: OBJECT METHODS 
      init <*USE*> (value: INTEGER); 
      inc <*USE*>(<*USE*> by: T)
    END:
  END Goo.

both instances below can be allocated on the stack

  WITH g = NEW(Goo.T), h = NEW(Goo.T) DO
    g.init(7); h.init(3);
    g.inc(h);
  END;

because the compiler can determine that the objects created by the
two calls to NEW are never used past the end of the WITH.

I contend that had USE been part of the language from day one, USE
would actually be the default, or possibly the only (!), mode for
passing the "self" parameter of an object method.

Wide use of USE mode implies that the convention of having an "init"
method return self or a "new" procedure or method that allocates the
object, is bad.  Following this convention means that objects of
those types cannot be allocated on the stack, or as we will see later,
combined with other objects to save allocations.  Greg agrees with
this and he plans on not using the convention of returning the object
in the init method anymore.  He doesn't plan to fix Trestle because
instances of its main type, VBT.T, are pretty heavy weight and are
not used in a way that the optimization applies.

Note that I expect USE mode parameters will be used primarily on object
types.  A parameter tagged USE REF X is very similar to VAR X, and
VAR X is useful in more settings.  Since an opaque REF type (<:  REFANY)
cannot be allocated, the usefulness of USE with those types is quite
limited.  For these reasons I would have no objection if USE could
only be applied to object types.

Further note the similarity of the above to an idiom that can already
used in Modula 3 to allow the compiler to allocate the array a on the
stack:

  WITH a = NEW(REF ARRAY OF X, n) DO
    Munge(a^);
  END;

The M3 compiler doesn't actually try to take advantage of this.

USE can also used to mark a field of an Object or a REF RECORD.  This
restricts the field to be assigned only as part of calling NEW on
the containing object.  After being set this field can only have its
fields accessed, be dereferenced (if it is a REF type) or be passed
as a USE parameter.  If the field itself is initialized with a call
to NEW then we know that the life time of the object referred to by
the field is exactly the same as the object the field is contained
in.  This allows the compiler to allocate the objects as a single unit.
Note that this works whether the parent object is being allocated on
the stack or the heap.  For example given

  INTERFACE Foo;
  TYPE T = OBJECT
      <*USE*> g1, g2: Goo.T;
    END;
  END Foo.

and

  x := NEW(Foo.T, g1 := NEW(Goo.T), g2 := NEW(Goo.T))

then the compiler may allocate the Foo.T and the two instances of Goo.T
as a single unit on the heap.  The two optimizations may be combined
as in

  WITH f = NEW(Foo.T, g1 := NEW(Goo.T), g2 := NEW(Goo.T)) DO
    f.g1.init(7); f.g2.init(3);
    f.g1.inc(f.g2);
  END;

where all three objects may be allocated together on the stack. 

To make this technique useful for opaque object types we actually have
to extend the language to allow one to give a more general default
field initializer.  Currently default field initializers are limited
to constant expression.  The minimal extension is to allow this to
be a call to NEW whose parameters are themselves constant expressions
or similar calls to NEW.  For example in:

  INTERFACE Foo;
  TYPE T <: OBJECT METHODS
     init <*USE*> ();
   END;
  END Foo.

rather than have Foo.init allocate the two fields g1 and g2, which
would not be possible if those fields were marked as USE, we can
allow all the objects to be allocated in one unit by allowing

  IMPLEMENTATION Foo;
  REVEAL T = BRANDED OBJECT 
      <*USE*> g1, g2: Goo.T := NEW(Goo.T);
     METHODS init <*USE*> ();
    END;
  END Foo.

This allows a client of Foo to allocate a Foo.T and have its two
associated Goo.T's allocated along with it as one unit.  Having a NEW
loop, e.g. if Goo.T has a field that is initialized as a NEW(Foo.T),
is a checked runtime error.  Note that the same NEW loop bug can occur
now with init functions, resulting in a stack overflow or an infinite
loop.

Note that with this technique we have managed to separate one reasons
for subtyping, avoiding extra allocations, from the more important
reason, that of data abstraction.  As Greg says on page 168 of his
book with reference to readers and writers:

  To achieve this pattern of information-hiding without partially
  opaque object types, it would be necessary to allocate each group
  of fields separately and link them together with additional references.
  This would require several allocations per writer, which would be
  costly.

We now have another technique to avoid allocations without the
restrictions of fitting each set of fields into a strict type hierarchy.

Unless there is a storm of protest, as part of the next round of
interface changes that we have planed here at SRC I would like to change
important "lightweight" objects (e.g. readers and writers, condition
variables and mutexes, others??) to follow the "no return value init
method" convention and to use the <*USE*> pragma.  This next round
of interface changes may not be visible to the outside for some time
but it may have bearing on your design choices for your own objects.

Garret Swart


======================================================================== 33 ===
Date:    Thu, 20 Feb 92 14:41:31 PST
From:    muller@src.dec.com (Eric Muller)
Subject: Floating point interfaces

SPwM3, p74:

  GENERIC INTERFACE Float (R); TYPE T = R.T;

  This generic interface provides access to the floating-point operations
  required or recommended by the IEEE floating-point standard
  [ANSI/IEEE Std 754-1985].  Consult the standard for the precise
  specifications of the procedures, including when their arguments are
  NaNs, infinities, and signed zeros, ...

So far so good, but:

1. The only mention of Logb is in the Appendix of the standard, and
   the first line of the Appendix says: 

	(This Appendix is not a part of ANSI/IEEE Std 754-1985, IEEE
	Standard for Binary Floating-Point Arithmetic.)

2. More seriously, the Appendix does not tell anything about ILogb.
   I am trying to find what ILogb (NaN), ILogb (Inf) and ILogb (+/-0)
   should be. 

   SPwM3 says of ILogb:

     Like Logb, but returns an integer, never raises ....

   On the other hand, the Appendix says:

     Logb(Nan) is a NaN, logb (Inf) is +Inf, and logb (0) is -Inf.

   What is an integer that is like a NaN ?  like +Inf ? like -Inf ?


-- 
Eric.



======================================================================== 34 ===
Date:    Fri, 21 Feb 1992 00:53:02 GMT
From:    treese@crl.dec.com (Win Treese)
Subject: Harbison's Modula-3 Book


Quantum Books in Cambridge, MA, now has Sam's book:

Newsgroups: misc.books.technical,wstd.quanbook
Path: news.crl.dec.com!deccrl!decwrl!uunet!world!quanbook
From: quanbook@world.std.com (Quantum Books)
Subject: New Release: Modula-3
Message-ID: <BJxz8G.KtC@world.std.com>
Organization: The World Public Access UNIX, Brookline, MA
Date: Thu, 20 Feb 1992 22:45:50 GMT

New Release

Modula-3
Samuel P. Harbison
(c) 1992, Prentice Hall
ISBN 0-13-596396-6
Paperback, 312 pages
$30.00

Author Samuel P. Harbison offers readers the first complete
guide to writing programs in Modula-3 - the newest member of
the Pascal family of languages.

Content Highlights include:

o A complete discussion of object-oriented programming, 
  including objects and methods, classes, and inheritance

o A set of programming conventions to help readers write more
  consistent and readable Modula-3 programs

o The SRC Modula-3 implementation run-time libraries

o Modula-3 language quick reference

o Concurrent Programming

o Modula-3's support for threads and semaphors


(from back of book)

-- 
Quantum Books		    | A Technical and Professional Bookstore   
----------------------------+------------------------------------------
Cambridge: 617-494-5042     | E-Mail:		 quanbook@world.std.com
Philadelphia: 215-222-0611  | Mailing List:      quanlist@world.std.com


======================================================================== 35 ===
Date:    Thu, 20 Feb 92 22:18:30 PST
From:    muller@src.dec.com (Eric Muller)
Subject: Re: Request mail-pool of volunteer "Experts"

In article <mod3sys.698634755@gonzo>, mod3sys@gonzo.cc.wwu.edu (modula3 system 
programmer) writes:
> I am beginning to work extensively in SRC Modula-3 v2.03, and herewith
> request names and address for anyone willing to answer minor questions,
> provide moral support, and so on.  I'd be willing to answer any such
> questions also:
> 		mod3sys@gonzo.cc.wwu.edu

m3-request@src.dec.com is always accepting questions.

If you need moral support, think about the poor SRCers who use
SRC Modula-3 all day long (if not all night long).

-- 
Eric, 8-) or 8-(, depending on the day.



======================================================================== 36 ===
Date:    21 Feb 92 01:12:35 GMT
From:    mod3sys@gonzo.cc.wwu.edu (modula3 system programmer)
Subject: Request mail-pool of volunteer "Experts"

I am beginning to work extensively in SRC Modula-3 v2.03, and herewith
request names and address for anyone willing to answer minor questions,
provide moral support, and so on.  I'd be willing to answer any such
questions also:
		mod3sys@gonzo.cc.wwu.edu
					-- S. Lee ODEGARD


======================================================================== 37 ===
Date:    Fri, 21 Feb 1992 18:44:54 PST
From:    David Goldberg <goldberg@parc.xerox.com>
Subject: Re: Floating point interfaces

In response to Eric's mail about the value of ILogb:

You'd like to have 2^ILogb(x)=x, and for x = infinity, the closest you
can come is ILogb(x) = LAST(INTEGER).  Similarly, ILogb(0) should be
FIRST(INTEGER);

There is no reasonable answer you can give for Ilogb(NaN).  This
brings up what seems to be a bug in the math interfaces, namely they
don't have a RAISES clause with FloatMode.Trap.  For example, Scalb
ought to RAISE Trap(Flag.Overflow) for large values of n.

Since ILogb(NaN) can't return NaN, I believe it should raise an
exception.  Either it should always raise Trap(Flag.Invalid), no
matter what FloatMode.behavior is, or else to avoid making a special case for
the meaning of Behavior, there should be some new EXCEPTION introduced
for Ilogb to RAISE in this case.

	-david




======================================================================== 38 ===
Date:    Fri, 21 Feb 1992 19:01:28 PST
From:    David Goldberg <goldberg@parc.xerox.com>
Subject: Re: the Fmt interface

While the question of whether to turn all runtime errors into EXCEPTIONS
has pros and cons, I'd like mention a special case that I think is especially
compelling and is fairly easy to implement:  an EXCEPTION for memory
allocation failures (this has been mentioned on this list before).

Here's an example of where this is crucial:  Your program builds an in-memory
cache for performance, but suddenly some other part of your program starts
to do a lot of allocations and runs out of memory.   The memory allocation
handler is just what you need:  It can trim down on the cache size, and then
retry the failing part of the code.

	-david


======================================================================== 39 ===
Date:    21 Feb 92 14:15:01 GMT
From:    piet@cs.ruu.nl (Piet van Oostrum)
Subject: Re: Problems installing for HPUX

>>>>> qs101@cl.cam.ac.uk (Quentin Stafford-Fraser) (QS) writes:

QS> I have been trying to build m3 v2.03 for HP-UX 7.0.

QS> The various makefiles etc took quite some tweaking, but I eventually got
QS> an 'm3' binary after 'm3make build_boot install_boot'

QS> Unfortunately, any attempt to use this produces:

QS> unrecognized option '-z4'
QS> usage: m3 [-?] [options] [-o pgm|-a lib|-c]     sources... objs... libs...

QS> Fatal Error: bad usage

QS>    Can anybody help ? Please?

I have been working on the port of 2.03 for HP-UX (8.0). I discovered some
problems in version 2.01(?), mailed it to the list but I think it got lost
somewhere. If you want to have the new list please get in touch with me so
I can mail it to you. I completed compiling the compiler, but there are
still some problems with libm3.
-- 
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')


======================================================================== 40 ===
Date:    Fri, 21 Feb 1992 10:36:19 PST
From:    Mike_Spreitzer.PARC@xerox.com
Subject: Re: Safe cheap objects for Modula 3

I've occasionally wondered about such a feature myself.  I'm surprised by the
differences between your proposal and what I came up with, and wonder why.
Here's what I would have expected.

The goal is to enable a compiler to prove that one value does not enable some
subsidiary value to outlive the first value.  For examples:

* For a particular field F of a record type R, where there's a variable r of
type R, wherever the field F is extracted from r, the extracted value is dead
by the time r is assigned to as a whole or r's scope is exited (which ever
comes first).  Similarly for elements of arrays.

* For a particular type R = REF T, wherever there's a value r of type R and r^
appears, the dereferenced value is dead by the time r must be dead.

* For a formal argument A of a procedure P, inside P's body the actual value
passed in A is dead by the time P returns (or is left by an exception).

(I mean "dead" as in dataflow analysis: a value is dead past the last reference
to it in the graph.  I've also used the phrase "must be dead", for something
closer to the source text: a value "must be dead" past the last place(s) in the
source text where a reference could be inserted.)

When this kind of statement can be made for every datatype that enables access
to one value from another, a compiler can then get the payoff: the ability to
prove that a value does not outlive a stack frame.  This is useful for
allocation in the stack, combining allocations (which actually includes
allocation in the stack, if you consider a stack frame as something that's
"allocated"), *and* checking that local procedures do not outlive their
containing activations.

So here's what it would look like for Modula-3.  I would use a word more
indicative of the discipline that's being indicated.  Let's say the pragma is
<*STACKED*>.  It can appear as an adjective in the following places, with the
indicated meanings:

*  ARRAY [Index] OF [<*STACKED*>] Element
    Wherever an element is extracted from such an array value, the extracted
value does not outlive the point(s) where the array value must be dead.

*  before a field name in a RECORD fieldlist
    Wherever that field is extracted from that type of record value, the
extracted value is dead by the point(s) where the record value must be dead.

*  [UNTRACED] REF [<*STACKED*>] Referent
    Wherever the referent value is extracted from such a reference value, the
extracted value is dead by the point(s) where the reference value must be dead.

*  before a formal parameter name in a procedure or method signature
    In the body of the procedure or method, the value received through that
parameter is dead by the time the body is exited.

*  after a method name in the Methods section of an object type
    In the body of the method, "self" is dead by the time the body is exited.

*  before a field name in an object type
    Wherever a value is extracted from that field of an object of that type,
the extracted value is dead by the point(s) where the object value must be
dead.

*  before a variable name in a VAR declaration
    No value extracted from this variable will outlive the extracting
activation of the block containing this declaration.  Note that a compiler
could automatically determine which variables are stacked regardless of whether
the programmer has declared them so; thus, these uses of <*STACKED*> are not
really necessary, and could be dropped from the proposal.

Note:

*  The methods of an object are always stacked: the procedure value of a method
cannot be extracted from an object.

*  Local procedures are always stacked.

*  It must be possible for the "self" parameter to object methods to be not
stacked; sometimes an object needs to insert itself in a data structure.

*  There is no need to prevent assignments to stacked fields of REF RECORDs,
unless we get into garbage collector implementation issues, which I hadn't
until reviewing Garret's message; I don't see how assigning to stacked fields
of REF RECORDs is more problematic that assigning to stacked arguments to
procedures, which Garret doesn't obviously prohibit.  Without a prohibition on
assignment, there's no need to generalize initialization.

*  A VAR T parameter is similar to (but *more* restricted than, in the
un-modified language) a VALUE <*STACKED*> UNTRACED REF T, modulo the ability in
the caller to coerce a variable into such an untraced reference.  If the caller
were further willing to notice such a call and place the runtime type code in
the right place, a VAR T parameter would be subsumed by a VALUE <*STACKED*> REF
T.


Examples of legality and illegality:

TYPE R = RECORD <*STACKED*>f1: T1; <*STACKED*>f2: T2 END;
TYPE T1 = ...;
TYPE T2 = ...;

PROCEDURE P1(r: R; f: T1; x: REF T1) =
    VAR <*STACKED*>g := r.f1;  (* Legal *)
    BEGIN
    IF r.f1=x^ THEN RETURN END;
    x^ := r.f1;  (* Illegal *)
                 (* the value passed in r is "dead" here *)
    IF g=x^ THEN RETURN END;
                 (* g is "dead" here. *)
    x^ := f;
    RETURN;
           (* the value passed in r "must be dead" here. *)
    END P1;

PROCEDURE P2(<*STACKED*>r: R; f: T1; x: REF T1) = ...;

PROCEDURE Top(r: R; f1: T1; x: REF T1) =
    VAR f2a = ...;
    VAR <*STACKED*>f2b = ...;
    BEGIN
    r.f1 := f1;                     (* Legal *)
    P1(R{f1:=f1; f2:=f2a}, f1, x);  (* Legal *)
    P1(r, f1, x);                   (* Legal *)
    P1(r, r.f1, x);                 (* Illegal *)
    P2(r, f1, x);                   (* Legal *)
    P2(R{f1:=f1; f2:=f2b}, f1, x);  (* Legal *)
    P1(R{f1:=f1; f2:=f2b}, f1, x);  (* Illegal *)
    RETURN;
    END Q;

Note that even though the T1 value that is extracted from r.f1 in the first
statement of P1 or P2 exists in memory after the activation of P, it does not
do so (if the illegal statements are ignored) because of its presence in the f1
field, but rather by a different path that does not place <*STACKED*>
restrictions.  Also, the reason the last call on P1 is illegal is that P1
doesn't guarantee that the value of its "r" parameter doesn't outlive the
activation (the <*STACKED*> restriction on field f2 alone isn't enough to
guarantee that the value passed to P1 in r.f2 doesn't escape the activation of
P1).


Here are some examples of usage:

PROCEDURE Find(l: List.T; ...): REFANY =
    PROCEDURE HardCase(r: REFANY): REFANY = ...;
    PROCEDURE EasyCase(r: REFANY): REFANY = ...;
    VAR <*STACKED*>TheCase: PROCEDURE (r: REFANY): REFANY;
    VAR ans: REFANY;
    BEGIN
    IF ... THEN TheCase := HardCase ELSE TheCase := EasyCase END;
        (* Legal because TheCase is stacked. *)
    WHILE l # NIL DO
        ans := TheCase(l.first);
           (* This is he only place a value is extracted from
              "TheCase"; the value is dead when the called
              body begins executing. *)
        IF ans#NIL THEN RETURN ans END;
        l := l.rest;
        END;
    RETURN NIL;
    END Find;

This is just a warmup, and doesn't need any  changes (recall that declaring
variables stacked is not really necessary), only a smarter compiler (and
relaxation of a language restriction).


For the next example, refer to section 3.7 (pp 85--87) of SPwM3, and consider a
client that wants to call tbl.map:

PROC Client(...) =
    VAR tbl: Table.T;
        (* ... and lots more local variables *)
    PROCEDURE Test(key: Key.T; value: Value.T): BOOLEAN
        = (* a body that references many of Client's
             local variables *);
    BEGIN
    ...
    tbl.map(NEW(Closure, apply := Test));
        (* Would be legal if Table had declared map's
           cl argument to be <*STACKED*>. *)
    ...
    END Client;

Suppose that when Client was first written, there was no call on tbl.map. A
year later, Client was modified slightly, and the call on tbl.map introduced.
Without this proposal, Client would have to be modified more extensively, to
move all the local variables of Client accessed by Test into a REF.


I could imagine adding a prohibition on assigning into stacked components, to
ease GC implementation.  I haven't worked it through, so I don't know that's
necessary to get reasonable GC implementations.

Does the SRC compiler do enough dataflow analysis to enable checking the
restrictions I'm suggesting <*STACKED*> could express?  If not, I suspect one
could get a decent approximation by local restrictions on the uses of a stacked
component (in the style Garret suggests, but with more rules).

Doesn't it seem right to make this kind of restriction (STACKED or USE) apply
to records, arrays, references, and objects in the way I've suggested (ie,
meaning nesting of lifetimes) rather than the special case for OBJECT and REF
RECORD fields that Garret suggests?


Mike


======================================================================== 41 ===
Date:    Fri, 21 Feb 92 09:26:51 PST
From:    <gnelson@src.dec.com>
Subject: Re: Safe cheap objects for Modula 3


Garret,

I like the idea of <*USE*> very much.

In order to allow <*USE*> to apply to fields of objects as well as 
to parameters, you propose to liberalize the rules for initializing 
fields at NEW time, allowing some non-constant expressions in field 
defaults where today only constant expressions are allowed.  I think 
it would be better to leave the rules for initializing fields alone,
and allow assignment to <*USE*> mode fields.  I don't see much benefit 
from prohibiting such assignments; the point of <*USE*> is to prevent 
a reference from escaping into a global, not to prevent it from being 
modified.

You seem inclined to think of <*USE*> only in regard to objects, 
but I think it would be exciting to change the field declaration

     buff: REF ARRAY OF CHAR

in a stream, replacing it with

     <*USE*> buff: UNTRACED REF ARRAY OF CHAR

after which DISPOSE(stream.buff) will be (or could be) safe!

In any case I suspect it is premature to expect to use <*USE*> 
uniformly in our interfaces.  USE is much too interesting to use yet.

Greg


======================================================================== 42 ===
Date:    21 Feb 92 13:30:28 GMT
From:    paul@ste.dyn.bae.co.uk (Paul Byrne)
Subject: Yacc files

I'm am trying to locate yacc and lex files for Modula2 and Modula3 syntax.
If anyone has a suitable syntax or can direct me to an ftp site please
e-mail me.

Thanks in advance

Paul Byrne


======================================================================== 43 ===
Date:    21 Feb 92 19:55:53 GMT
From:    dagenais@vlsi.polymtl.ca (Michel Dagenais)
Subject: Sparc binaries of modula 3 SRC-2.03

Since at least one request echoed my offer, i packaged the sparc binaries
of Modula 3 SRC-2.03 (with all the libraries). It is now available for
ftp from wotan.vlsi.polymtl.ca in pub/modula3-2.03-sparc.tar.Z. When
uncompressed it takes 30MB and must be installed (or soft linked) in
/usr/local. Then, you can link /usr/local/bin/m3 to
/usr/local/modula3-SRC-2.03/run/poly/sun4.0-sparc/bin/m3 and do the same
thing for the other binaries and the man pages. The compiler will find the
library modules and the include files in their location if you install
everything as prescribed. This setup might sound strange but it is the
result or a few years experience with a large installation where software
packages must run on many platforms, with some locally developed variants
and frequent version upgrades. Enjoy and let me know if you have problems,
our ftp account is not very active and sometimes gets rusty.

--
---------------------------------------------------------------------

Prof. Michel Dagenais			    dagenais@vlsi.polymtl.ca
Dept of Electrical and Computer Eng.
Ecole Polytechnique de Montreal		    tel: (514) 340-4029

---------------------------------------------------------------------


======================================================================== 44 ===
Date:    Mon, 24 Feb 92 13:05:06 PST
From:    <swart@src.dec.com>
Subject: Re: Safe cheap objects for Modula 3


This message attempts to clear up some of the problems of understanding
that Greg and Mike had with the previous message.  I had a good
conversation with Bill Kalsow on Friday and I append a couple of ideas
that came out of that.  I should further note that I am not a member
of the Modula 3 design or implementation team and do not speak for
them, though of course I am trying to influence them!

Here goes.

Greg says:

    The point of <*USE*> is to prevent a reference from escaping into
    a global, not to prevent it from being modified.

Mike says:

    The goal is to enable a compiler to prove that one value does not
    enable some subsidiary value to outlive the first value.

Those are both subgoals.  The real goal of USE is to allow the compiler
to predict the life times of objects well enough so that it can allocate
and free them more efficiently.  Hmm, but that is also a subgoal.  The
REAL goal of USE is to let programmers feel free to use objects to
represent any data type they want and not feel constrained by the cost
of allocation and garbage collection.  (Don't even consider for a moment
that the real REAL goal is to nullify an important advantage C++ has
over Modula 3.)

The main ways the compiler can take advantage of life time predictions
are:  If an object can be shown to live no longer than the current
stack frame it can be allocated on that stack frame.  If two objects
can be shown to have the same life time they can be allocated together,
as a single GC unit on the heap or as a single unit on the stack.

Greg says:

    I think it would be better to ... allow assignment to <*USE*> mode fields

Mike says:

    There is no need to prevent assignments to stacked fields of REF RECORDs,

The reason to prevent assignments to USE mode fields is because it
would then allow the life time of the object referred to by the field
to be shorter than the life time of the containing object.  Assuming
that the two objects are allocated together, we would not get timely
collection of the object with the contained object.  If timely
collection of such objects is not important, then this restriction
can be relaxed.

However another reason to prohibit assignment to USE fields, and
override to the field on NEW, is that actual the type of the object
becomes fixed at compile time, this might allow one to inline
method invocations.

Greg says:

    I think it would be better to leave the rules for initializing
    fields alone

Mike says:

    Without a prohibition on assignment, there's no need to generalize
    initialization.

The reason for allowing NEW on initializers not directly related to
the rule for not allowing assignment.  It is instead to make it more
likely that separate objects will have the same life time and thus
allow them to be combined.  Remember the example from my original
message:

  INTERFACE Foo;
  TYPE T = OBJECT
      <*USE*> g1, g2: Goo.T;
    END;
  END Foo.

and

  x := NEW(Foo.T, g1 := NEW(Goo.T), g2 := NEW(Goo.T))

because the NEWs are all done at one time and at one place the compiler
can easily determine that the objects have the same life time and store
them together.

But when if Foo.T is opaque?  E.g.

  INTERFACE Foo;
  TYPE T <: OBJECT METHODS
     init <*USE*> ();
   END;
  END Foo.

Then the client of Foo cannot assign to g1 and g2 and it doesn't know
from Goo.  In the current language without NEW on initializers the
client would allocate Foo.T and then call Foo.T.init to initialize
the object, which could then call NEW and assign the result to the
fields.  That works fine, but the three objects have different life
times and the compiler, without heroic inter-procedural analysis, could
not determine that the objects could be stored together at the point
it was allocating an instance of Foo.T.

Note that the alternative of allocating a Foo.T, along with the Goo.T's,
in a create function Foo.New is bad because it disallows the
optimization of putting the Foo.T on the stack and it doesn't compose
if Goo.T turns out to be an opaque object with fields.

My proposal solves the problem

  IMPLEMENTATION Foo;
  REVEAL T = BRANDED OBJECT 
      <*USE*> g1, g2: Goo.T := NEW(Goo.T);
     METHODS init <*USE*> ();
    END;
  END Foo.

because at link time the implementation would know that every object
allocated as a Foo.T always has two Goo.T's stored after it and it
would know the length of a Goo.T and any types stored after it
so that when allocating a Foo.T the total space needed could be
allocated at one go and the cross links made.

One could limit NEW to being used as an initializer only for USE fields
but then USE would have to be promoted from pragma-hood to the language
itself.

Greg says:

    I think it would be exciting to change the field declaration
    
         buff: REF ARRAY OF CHAR
    
    in a stream, replacing it with
    
         <*USE*> buff: UNTRACED REF ARRAY OF CHAR
    
    after which DISPOSE(stream.buff) will be (or could be) safe!

Only if stream was allocated in this procedure, consider

  PROCEDURE P(<*USE*> stream: Stream; VAR b: ARRAY OF CHAR) =
    BEGIN
      DISPOSE(stream.buff);
    END P;

But do we really want programmers to get back into the job of explicit
memory deallocation?  Why not get rid of the UNTRACED and have the
compiler generate the DISPOSE for you when it recognizes that the old
value of stream.buff is dead?

Also note that all this technique saves you is the cost of GC on
stream.buff, not the cost of allocation or deallocation.  I'll bet
a lot of examples could be handled by

  INTEFACE Stream;
  TYPE Private <: ROOT;
    T <: Private OBJECT
           <*USE*> buff: REF ARRAY OF CHAR := NIL;
           (* Clients should allocate this but they should not look inside! *)
         METHODS
           init <*USE*> ();
         END;
  END Stream.

A client could then say:

  WITH stream = NEW(Stream.T, buff := NEW(REF ARRAY OF CHAR, 5000)) DO
    ...
  END;

which could allocate the Stream and the buffer on the stack.  If one
could get by with a fixed size buffer, then one can hide the buffer
inside the stream. 

Mike says:

    Does the SRC compiler do enough dataflow analysis to enable checking
    the restrictions I'm suggesting <*STACKED*> could express?  If not,
    I suspect one could get a decent approximation by local restrictions
    on the uses of a stacked component (in the style Garret suggests,
    but with more rules).

If we are to get something like this accepted and implemented in every
silly compiler, we have to be able to do it without real data flow
analysis, that is, via simple local checks like the ones I proposed.
The checks have to be expressed in terms, not in terms of complicated
rules like whether a variable is dead, but by simple restrictions a
programmer can remember and can deal with.

Mike says:

    PROCEDURE Find(l: List.T; ...): REFANY =

It's too easy to fake this for it to be a telling example for me.
E.g.

PROCEDURE Find(l: List.T; ...): REFANY =
    PROCEDURE HardCase(r: REFANY): REFANY = ...;
    PROCEDURE EasyCase(r: REFANY): REFANY = ...;
    TYPE Case = (Easy, Hard)
    VAR theCase: Case;
    PROCEDURE TheCase(r: REFANY): REFANY =
      BEGIN
        CASE theCase OF
        | Case.Easy: RETURN EasyCase(r);
        | Case.Hard: RETRUN HardCase(r);
        END;
      END TheCase; 
    VAR ans: REFANY;
    BEGIN
    IF ... THEN theCase := Case.Hard ELSE theCase := Case.Easy END;
    WHILE l # NIL DO
        ans := TheCase(l.first);
        IF ans#NIL THEN RETURN ans END;
        l := l.rest;
        END;
    RETURN NIL;
    END Find;

Mike says:

    PROC Client(...) =

The problem is that Table.T.map has the wrong signature.  It should
accept a procedure, which would invariably be an internal procedure,
rather than an object.  (Though in fact one can think of a passed
internal procedure as a funny kind of object.  Think of the up level
display as the private fields of the object.)  I am working with people
here to try and fix these problems, some of which were introduced when
interfaces were translated from Modula 2+, which did not have objects
and did not allow internal procedure to be passed as arguments, into
Modula 3.

Bill reminded me that a further use of USE is to mark a PROCEDURE
argument.  This ensures the client that it is okay to pass an internal
procedure as an argument.  I originally suggested to the M3 committee
that internal procedures should have a different type than an external
procedure with the same signature to get compile time checking of
correct usage.  This is similar but less fool proof. 

Bill brought up a few other very interesting points:

- Is allocation, deallocation, and GC overhead a large part of the
  runtime of a Modula 3 application?

    My main experience with this has been with our Modula 2+ system
    where GC overhead sometimes consumed over 50% of the CPU cycles.
    Admittedly the collector was concurrent, designed for a
    multiprocessor and was optimized for small real time rather than
    small CPU time.  The Modula 3 collector has very different
    characteristics but we both expected that a study would show that
    this is important.

- Instead of trying to get rid of GC'ed objects (by combining them
  or putting them on the stack) wouldn't it be better to just make
  objects cheaper?

    Yes but I don't see any way to make them cheap enough to use really
    freely.  That is one of the arguments people have had against
    languages that insist on everything being a pointer, e.g. ml or
    lisp.

- How much will this technique save on existing objects?

    I can only guess, but I would guess not much.  My guess is that
    the savings we get will come from allocating readers and writers
    on the stack and combining conditions with their containing objects.
    (Mutexes are often already combined by making them supertypes of
    the client type, which I think is a bit odd; I would rather see
    them as separate fields.)  Remember this is a wild guess based
    on not too much information.

    I suspect the primary advantage will be that it will allow one
    to use object types in places where they cannot be used now
    because of efficiency considerations.

- Does USE have any value to the programmer as part of a specification
  of an interface or is it just a compiler hint?

    More generally, what does a programmer wants to know about the
    use of the arguments:

      What operations might be called on this object while the call
      is outstanding?  Update or just read operations?
      
      What operations might be called on this object after the call
      returns?  Update or just read operations?

   USE says that there are no operations in the second category.  This
   is a generally useful piece of information to the programmer.  Note
   that for immutable objects this can be an over specification because
   one normally wouldn't care about read operations taking place after
   the call returns.

- Couldn't USE end up being an over specification in some places?  That
  is, couldn't it end up prohibiting some new implementations?

    As above, it can lead to over specification on immutable types.
    Consider the Text interface.  In M3, Text's are implemented as REF
    ARRAY OF CHAR, while in Modula 2+ they are implemented as linked
    structures.  Text.Cat in M3 just access its arguments in
    constructing a new text while in Modula 2+ the arguments are pointed
    to by the result.  Marking the arguments of Text.Cat with USE would
    thus work for the current M3 implementation but would not allow
    a Modula 2+ style implementation.

    A sneaky way around this problem is to use <*USE*> on all immutable
    input parameters, but have implementations with USE define a generic
    interface:

    GENERIC INTERFACE GiveMe(Type);
      (* With Type.T <: REFANY. *)

      PROCEDURE P(<*USE*> r: Type.T): Type.T;
        (* Returns NIL if obj is not a top level object otherwise
        returns obj again.  If a non NIL value is returned the result
        may be safely used in any assignment operation.  *)

    END GiveMe.

    The implementation of GiveMe would be the identity on
    implementations without USE.  On implementations with USE it will
    check the address to see if it points to the start of a heap object.

    An implementation of an operation on an immutable type that wants
    to keep a copy of its argument, like a Modula 2+ style Text.Cat,
    would then call the type's copy method.  This method would take
    its argument as USE and return an object "equal" to its argument.
    This method could return GiveMe.P(self) if it is non NIL and
    allocate and initialize a new object otherwise.

Garret Swart


======================================================================== 45 ===
Date:    25 Feb 92 18:31:01 GMT
From:    hudson@cs.umass.edu (Rick Hudson)
Subject: Re: Safe cheap objects for Modula 3

swart@src.dec.com writes:

> The main ways the compiler can take advantage of life time predictions
> are:  If an object can be shown to live no longer than the current
> stack frame it can be allocated on that stack frame.

Yes, and pending studies to the contrary, I would agree and such
optimization might be very valuable.

> If two objects
> can be shown to have the same life time they can be allocated together,
> as a single GC unit on the heap or as a single unit on the stack.

In a copy collector, allocating two objects with one heap allocation might
save the cost of incrementing the allocation pointer, but this isn't much of
an advantage.  If both objects die at the same time, whether they were
allocated as one unit or not, makes no difference.

The arguments that continued were well stated but assumed that there
was an advantage to allocating single GC units. 

Later on you discuss the following:

> - Instead of trying to get rid of GC'ed objects (by combining them
>   or putting them on the stack) wouldn't it be better to just make
>   objects cheaper?
> 
>     Yes but I don't see any way to make them cheap enough to use really
>     freely.  That is one of the arguments people have had against
>     languages that insist on everything being a pointer, e.g. ml or
>     lisp.

The folk lore that GC style object allocation is not cheap seems to continue,
mostly being based on experience with non-generational or reference count
style garbage collectors.

Modula-3 differs greatly from Lisp in that it is statically typed. This allows
a lot of the overhead of GC to be done away with. For example, look at the
Gabriel benchmark "destruct" which was designed to test the
speed of mutating objects in Lisp by assigning integers into slots in objects
(actually cars in cons cells).  If the Lisp has a generational GC it will
spend a lot of time dealing with remembered set manipulations when the objects
being stored are not pointers. Lisp has no way to tell this. To a great
extent, remembered set processing is what the bench was designed to test.  In
Modula-3 we would know we were storing integers and 94% of the remembered set
activity would be eliminated.

Remembered set activity is also worth noting with regards to something said in
an earlier letter. There was a discussion on how to best initialize objects.
In a generational GC, time must be spent each time a pointer is stored to
determine if the slot being stored into is in an older generation than the
object the pointer refers to. If we know the object being stored into is the
youngest object in the system we can eliminate this check. The current
definition of NEW, when used with initialization values, allows such
optimization. I currently do not know how valuable this optimization will be
and would not like to see anyone change their current coding styles to take
advantage of this optimization, but I just mention it as a case where changing
coding style to facilitate one optimization on one compiler might 
defeat another optimization on another compiler.

--

                Richard L. Hudson, Research Associate
                University Computing Services
                Lederle Graduate Research Center
                University of Massachusetts
                Amherst, MA  01003
                (413) 545-1220; Hudson@cs.umass.edu


======================================================================== 46 ===
Date:    Tue, 25 Feb 1992 07:41:51 PST
From:    Mike_Spreitzer.PARC@xerox.com
Subject: Re: Safe cheap objects for Modula 3

We actually agreed on the goal of predicting lifetimes of objects well enough
to allocate and free them more efficiently (and I also introduced the goal of
expressing the restriction on local procedures so that runtime checks need not
be done).  What I was trying to say is that that goal sets up a subgoal that
has to be proven by induction over the structure of the data, and the more
kinds of arcs in a type graph that can carry a nesting-of-lifetime restriction,
the more cases where that proof will go through.

The idea of inlining method invocation is attractive, but I suspect this trick
will not get you very many cases.  Most of the method inlining will require
inter-procedural analysis.

You don't need to allow NEW in initializers to allocate objects together.
Consider your (non-opaque) example of Foo.T and Goo.T.  Because your
formulation of USE is so tight, the compiler could react to the declaration
that the g1 and g2 fields of a Foo.T are USE by always allocating space for two
Goo.T's with every Foo.T, and translating every "x.g1 := NEW(Goo.T)" (assuming
you relaxed just enough to allow assignments to USE fields) into assigning the
address of the first Goo.T space into x's g1 field.  This space would go unused
only when the programmer writes "x.g1 := Proc(...)" (which, as you've noted, is
a weakness in any case).  My understanding of memory managers is that the cost
per object is much more significant than the cost per byte of object size, so
this could be a good trade-off.

Why does the current language require initialization to use only constant
expressions?  If we can change that enough to allow NEW in initialization, how
much else is equally easy to allow?

I presume you mean to prohibit assignment through REFs to whole RECORDs that
contain (RECORDs that contain ...) USE fields.

Calling USE an "over-specification" seems wrong.  Using USE says something.
Whether the author wants to say it is up to the author.  If the author wants to
say it, it is not an ober-specification.  Put another way, the question is,
"can USE be used unwisely?".  The answer is "yes", and that's not a
condemnation of USE.


======================================================================== 47 ===
Date:    Tue, 25 Feb 92 10:14:04 PST
From:    <swart@src.dec.com>
Subject: Re: Safe cheap objects for Modula 3


    What I was trying to say is that that goal sets up a subgoal that
    has to be proven by induction over the structure of the data, and
    the more kinds of arcs in a type graph that can carry a
    nesting-of-lifetime restriction, the more cases where that proof
    will go through.

Good point.  I was trying to be a bit more hard-ass and only look at
arcs that carry "equivalent lifetime" restrictions.

    The idea of inlining method invocation is attractive, but I suspect
    this trick will not get you very many cases.  Most of the method
    inlining will require inter-procedural analysis.

One can inline a method invocation when one can statically statically
determine the actual type of an object.  There are two simple cases
where this can be done, when an object is allocated as the expression
of a WITH statement, E.g.

  WITH o = NEW(Foo.T) DO
    o.m1()
  END;

or when an object is referred to by a field marked USE, using the rule
that USE fields are only assigned to by the default value specifier.

    Because your formulation of USE is so tight, the compiler could
    react to the declaration that the g1 and g2 fields of a Foo.T are
    USE by always allocating space for two Goo.T's with every Foo.T

Just knowing the type declaration of g1 and g2 only gives a lower bound
on the size of the objects being referred to.  One could always assign
a Moo.T to a field of type Goo.T where

  Moo.T = Goo.T OBJECT cow: ARRAY[1..1000] OF CHAR; END;

A Moo.T^ would certainly not fit in the room reserved for a Goo.T^.
Your idea could still work in the case where one is careful to declare
the actual type of the object rather than a super type.  This mean
that the extra space would go unused either if the programmer writes
"x.g1 := Proc(...)" or when the programmer writes "x.g1 := NEW(Goo.T
OBJECT ...  END)".

    Why does the current language require initialization to use only
    constant expressions?  If we can change that enough to allow NEW
    in initialization, how much else is equally easy to allow?

It was my understanding that this discussion eventually ends up as
part of the whole object initialization conundrum (what order should
initialization calls be made in, why not implicitly call the init method
after allocation) which Greg can explain much better than I. The current
restrictions, and my extension, both have the property that a NEW never
involves executing any user written code so that the interesting issues
are avoided.

    I presume you mean to prohibit assignment through REFs to whole RECORDs tha
t
    contain (RECORDs that contain ...) USE fields.

Yes.

    Calling USE an "over-specification" seems wrong.

You are right.  The question I was trying to get at was whether USE
is a useful part of a procedure specification.  I guess my conclusion
is that for mutable objects it is useful but for immutable objects
it is not a useful because it says more than a programmer needs to
say.  The trouble is that the compiler is interested in USE and marking
a procedures parameters with USE allows the procedure to be used more
efficiently.  Thus it is tempting to use it inappropriately.

    I also introduced the goal of expressing the restriction on local
    procedures so that runtime checks need not be done

I've come to the conclusion that procedures passed as arguments should
always be passed in USE mode, thus always allowing local procedures
to be used as arguments.  If an interface accepts a procedure in any
other mode the interface designer screwed up: it should be accepting
a closure object instead.

USE mode procedures should be used in cases where you promise to be
done with the procedure before the call returns, e.g. Table.T.map.
Closures should be used in cases where that promise cannot be made,
e.g. Thread.Fork.  Thus if good programming practice is being used
there should never be a runtime check that a procedure parameter is
assignable.  I think I can say something still stronger:  When good
programming practice is being used the only variables of type PROCEDURE
should be parameters.  (You mean Pascal got it right?  Not really,
because Pascal doesn't have objects.)

[Note that there are examples where passing a procedure and a REFANY
is more efficient than using an object because it avoids an extra
allocation.  E.g. instead of

  TYPE MyClosure = Thread.Closure OBJECT text: TEXT 
       OVERRIDES apply = MyApply END;
  Thread.Fork(NEW(MyClosure, text := t))

one could avoid the NEW by passing the TEXT as a REFANY

  Thread.Fork(MyApply, t)

But in most cases the designer of the interface can get the allocation
back by giving the closure an opaque supertype and using that for the
implementation's own data.  For example, Thread.Closure could be
implemented as subtype of Thread.T.]

Garret


======================================================================== 48 ===
Date:    Tue, 25 Feb 92 09:58:37 PST
From:    mjordan@src.dec.com (Mick Jordan)
Subject: Re: Safe cheap objects for Modula 3

Modula-3 provides a lot of support for abstraction that, if used 
extensively, makes the generation of high quality code for separately
compiled modules essentially impossible. E.g. "virtual" method calls
that arent, opaque supertypes, NARROW calls to leaf types, inline
procedures, NEW calls that could be allocated on the stack and so on.
Trying to fix these problems with pragmas is, I believe, a mistake.
Instead, we should focus on generating optimal code for complete
programs, where the abstraction scaffolding can be torn down.

Recently, I posted a message alluding to a tool that would perform
procedure inlining. In practice this tool is the beginning of a whole
program optimiser for Modula-3, which is focussed on the kinds of
transformations that the USE pragma is aimed at.

Currently the tool is capable of the following optimisations:

0. Removing the addresssing overhead of opaque supertypes, which comes
   for free by compiling with knowledge of the concrete revelations.

1. Removing unreachable procedures, including those that are merely
   specified as method overrides if they can never be invoked.

2. Translating method calls into procedure calls if only one procedure
   value is possible. T.m is a trivial case of this.

3. Translating TYPECASE into CASE, when all the type labels are
   disjoint. (This can be the basis of method inlining, when
   more than one procedure value is possible.)

In its present form the tool does not do dataflow analysis; it is
suprising what can be achieved with only simple analysis. 
It works on big programs, provided you have enough VM, e.g. BadBricks
and, in its current form, generates Modula-3 as output (which is
something of a limitation but has some virtues). The tool is
based on the Modula-3 toolkit ASTs, and I plan to ship it with
the 2.0 toolkit later this year. Mostly due to optimisation 3,
I get a factor of two speedup in the toolkit compiler itself, which
I find pretty exciting.

Mick Jordan
 


======================================================================== 49 ===
Date:    Tue, 25 Feb 92 14:40:25 EST
From:    wyant@centerline.com(Geoff Wyant)
Subject: Re: Safe cheap objects for Modula 3

I agree with Rick Hudson. It seems like a lot of thought
is being expended on how to work around the garbage
collector. I don't believe that garbage collection HAS to 
be that expensive that pragmas need to be invented to
avoid it. Modern generational collectors can make allocation
no more expensive than incrementing a pointer. Deallocation
can be somewhat more expensive, but with a tuneable
collector such as the one that GNU M3 project is working on,
the costs should be quite controllable. 




Geoff Wyant
wyant@centerline.com
Centerline Software, Inc.
(Formerly Saber Software, Inc)
10 Fawcett Street
Cambridge, Ma.




======================================================================== 50 ===
Date:    Tue, 25 Feb 1992 21:25:55 GMT
From:    tia@sunb2.cs.uiuc.edu (Too-Seng Tia)
Subject: questions on modula-3


I am trying to learn Modula-3 (by reading some sample programs :( ). 
I have a couple of questions :

(1) Are there any good textbooks on Modula-3?

(2) We have version 1.6 of SRC Modula-3 compiler. Is there a language manual
    for the compiler?

(3) I tried to compile the following module taken from an article in the
    BYTE magazine (Nov 90), but can never get it to compile. Can someone
    tell me whether I have made a mistake somewhere? The compiler tells me
    that I have a syntax error (extra tokens) in the line with "MODULE Point;"

==================================================

INTERFACE Point;
  TYPE
    T<:Public_T;
    Public_T=OBJECT
      METHODS  
      	PosX( ):REAL; 
      	PosY( ):REAL;
      END;
  <*INLINE*> PROCEDURE New(x,y:REAL):T;
END Point.
MODULE Point;

  REVEAL
    T=Public_T BRANDED OBJECT
      X,Y:REAL;
    METHODS  
      PosX := PosXProc;
      PosY := PosYProc;
    END;
  PROCEDURE New(x, y:REAL):T=
    BEGIN
      RETURN NEW(T,X:=x,Y:=y);
    END New;
  PROCEDURE PosXProc(p:T):REAL=
    BEGIN RETURN p.X; END PosXProc;
  PROCEDURE PosYProc(p:T):REAL=
    BEGIN RETURN p.Y; END PosYProc;
BEGIN
END Point.

====================================================

(4) I was trying to implement a tree module. Here are my interface and
    part of the module :


INTERFACE Tree;

  IMPORT Info, Text;

  TYPE T<:Public;
  Public=OBJECT
  METHODS
    make (): T;
    empty (): BOOLEAN;
    insert (node: T; key: TEXT);
    setInfo (info: Info.T);
    setLeft (left : T);
    setRight(right: T);
    info (): Info.T;
    left (): T;
    right (): T;
    print ();
  END;

END Tree.
       

MODULE Tree;

  IMPORT Info, Text, Wr, Stdio;

  REVEAL T=Public BRANDED "Tree.T" OBJECT
    infoPtr: Info.T;
    leftPtr, rightPtr: T;
  OVERRIDES
    make := make;
    empty := empty;
    insert := insert;
    setInfo := setInfo;
    setLeft := setLeft;
    setRight := setRight;
    info := info;
    left := left;
    right := right;
    print := print;
  END;

==============================

	If I replaced the keyword "OVERRIDES" with "METHODS",
I get some compilation errors. If I omit "OVERRIDES" and all the 
method := method that follows it altogether, I get some "illegal instruction"
error during runtime. My question is - why do I need the "OVERRIDES"?
I suppose in object-oriented programming, there are many occasions where
we want to override some methods in the superclass. But I don't understand
why I need it here.


	Any help is greatly appreciated.

	Thanks.





======================================================================== 51 ===
Date:    Tue, 25 Feb 92 16:06:20 PST
From:    muller@src.dec.com (Eric Muller)
Subject: Re: questions on modula-3

In article <1992Feb25.212555.15707@sunb10.cs.uiuc.edu>, tia@sunb2.cs.uiuc.edu (
Too-Seng Tia) writes:

> (1) Are there any good textbooks on Modula-3?

There are two books on Modula-3:

@book		(m3-Nel91,
title		= "System Programming with Modula-3",
editor		= "Greg Nelson",
publisher	= "Prentice Hall",
isbn		= "0-13-590464-1",
year		= 1991,
what		= "The bible for Modula-3.  Includes the language
                   reference manual and papers on the I/O library,
                   threads, and the Trestle window system."
)

@book		(m3-Har92,
title		= "Modula-3",
author		= "Samuel P. Harbison",
publisher	= "Prentice Hall",
isbn		= "0-13-596396-6",
year		= 1992,
what		= "A complete Modula-3 textbook covering the full
                   language, with examples and exercises.  Includes a
                   style manual and a user's guide for SRC Modula-3."
)


The first is a reference and deals with some advanced topics.  The
second should now be available in all bookstores and is a textbook (I
got one yesterday at the downtown branch of the Stanford Bookstore).


> (2) We have version 1.6 of SRC Modula-3 compiler. Is there a language manual
>     for the compiler?

Version 1.6 is now obsolete.  In addition to a number of bugs that
have been fixed, it implements an earlier version of the language than
described in the two books above.  You should really get 2.03 from
gatekeeper.dec.com, in pub/DEC/Modula-3.  If you insist on using 1.6,
the language implemented by that version is described in:

@techreport     (m3-CDG*89,
author          = "Luca Cardelli and James Donahue and Lucille Glassman
                   and Mick Jordan and Bill Kalsow and Greg Nelson",
title           = "Modula-3 Report (revised)",
number          = "52",
type		= "SRC report",
institution     = "System Research Center, Digital Equipment Corporation",
address         = "Palo Alto",
month		= nov,
year            = 1989,
howtoget	= "Via anonymous ftp on gatekeeper.dec.com, in
                    pub/DEC/Modula-3/Report.ps. This file has been
                    formatted for an Apple Laserwriter. The files
                    Report{1,2,3}.ps are also the report, in three
                    postscript files, to accomodate small printers.
                   On paper, by sending a mail to src-report@src.dec.com.",
what		= "This report is {\em the} definition of the language."
)

In addition, SRC Modula-3 has some release notes.  You should be able
to get them from person who installed SRC Modula-3 at your site.  If
not, the 1.6 release notes can still be found in
gatekeeper.dec.com:pub/DEC/Modula-3/m3-1.6/dist-1.6.tar.Z.  The 2.0
release notes are in
gatekeeper.dec.com:pub/DEC/Modula-3/m3-2.0/doc-2.03.tar.Z.


> (3) I tried to compile the following module taken from an article in the
>     BYTE magazine (Nov 90), but can never get it to compile. Can someone
>     tell me whether I have made a mistake somewhere? The compiler tells me
>     that I have a syntax error (extra tokens) in the line with "MODULE Point;
"

Could it be that you have everything in one file ?  SRC Modula-3
requires that each compilation unit be in a separate file; the
interface I must be in the file I.i3.  There is also the convention
that the module M be in the file M.m3.

> (4) I was trying to implement a tree module. Here are my interface and
>     part of the module :
> 
> ...
>
> 	If I replaced the keyword "OVERRIDES" with "METHODS",
> I get some compilation errors. If I omit "OVERRIDES" and all the 
> method := method that follows it altogether, I get some "illegal instruction"
> error during runtime. My question is - why do I need the "OVERRIDES"?
> I suppose in object-oriented programming, there are many occasions where
> we want to override some methods in the superclass. But I don't understand
> why I need it here.

What are the compilation errors ?  Could it be that the procedures
"make" and so on do not have the proper declaration ? They should be
like:

PROCEDURE make (self: T): T = 
   ...

(where any identified instead of self is ok).

If you just remove OVERRIDES and what follows it, instances of the
type do not have procedures associated with the methods (i.e. the
procedure associated with the method is NIL) and you get a checked
runtime error (i.e. the program somehow crashes).  This also explains
why you need an OVERRIDES: to associate some procedures to the methods.

-- 
Eric.



======================================================================== 52 ===
Date:    Wed, 26 Feb 1992 11:20:51 PST
From:    Hans_Boehm.PARC@xerox.com
Subject: Re: Safe cheap objects for Modula 3

Let's keep things in perspective.  There is a significant cost to allocating
collectible storage rather than stack allocating storage.  At a minimum, the
first read access to every newly allocated cache line in the heap is likely to
miss (unless writes force cache reloads, which has other costs).  Furthermore
heap allocation with a direct mapped cache is likely to trash everything else
in the cache periodically.  You may need some locking or synchronization on
allocation, or risk fragmenting the heap by dividing it up on a per thread
basis.

On the other hand, stack allocating memory that is known not to outlive a
procedure activation is also dubious in general.  David Chase had a paper a
while back describing some of the things that can go wrong.  The most obvious
one is that the procedure may allocate a gigabyte of data, most of which dies a
long time before the procedure exits.  Nonetheless, I think it's profitable to
do so, when you can determine it's safe.  If your collector supports optional
explicit deallocation, then that can also alleviate the cache problems, and is
probably less dangerous, but more expensive in other respects.

Hans


======================================================================== 53 ===
Date:    Thu, 27 Feb 92 13:47:47 -0500
From:    Norman Ramsey <nr@Princeton.EDU>
Subject: SRC M3 implementation of exceptions

Apologies if this article has already appeared.  I fear our news posting
software is wonky again.

A while back, a newcomer asked about the SRC M3 implementation of
exceptions using setjmp and longjmp.  As noted in the installation
guide, assignments to variables may have been undone when the
exception-handling code executes.

I've actually been bitten by this problem a couple of times, most
frequently in lexical analysis, which has to perform nontrival
computations when handling Rd.EndOfFile.  I need to compile the code
with optimization because it's a performance bottleneck.  What I do to
fix the exception problem is to take the address of every scalar
variable that's used in an exception handler.  The address-taking code
doesn't actually have to be executed very often (or even at all); as
long as the compiler thinks the address of a variable might be taken,
it won't allocate the variable to a register.

So, would the M3 compiler people consider doing automating this
process?  Adding the following code to an exception handler should do
it:

   pointless_global_variable = (unsigned) &n + (unsigned) &m + ... ;

I think the cost of executing this code in every exception handler
should be acceptable; it should be lost in the noise of the
setjmp/longjmp overhead.


Norman Ramsey
nr@princeton.edu


======================================================================== 54 ===
Date:    Thu, 27 Feb 92 15:58:27 +0100
From:    Piet van Oostrum <piet@cs.ruu.nl>
Subject: Article "Modula-3 type systems"

I am trying to locate the article "The Modula-3 type System". I think by
Cardelli. I have had it but can't find it back. It would be nice if
anybody had a machine-readable version, even better if it had been updated
with respect to the language changes. I want to give it as a handout to my
students on the "Object oriented programming" course.

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')


======================================================================== 55 ===
Date:    Thu, 27 Feb 92 06:57:51 PST
From:    bates@awsil4.boeing.com
Subject: X11R4 Ultrix compatibility

Does anyone know what version of X11 comes with Ultrix 4.1 and 4.2?
(This if for the DEC Station 3100.)
The m3-1.6 X11R4 demos won't link to the X11 libraries I got with
Ultrix.  Both the Ultrix release notes and DEC support claim that
this is fully compatible with X11R4.  But the links fail with
undefined symbols,  the most common of which is XtAppInitialize.
The C header files  which came with Ultrix are also missing
XtAppInitialize and a couple of others at the place where the 
m3 interface has them. Other nearby procedures match between the 
C header files and the m3 interfaces.  

Rod Bates


======================================================================== 56 ===
Date:    27 Feb 92 14:38:47 GMT
From:    moss@cs.umass.edu (Eliot Moss)
Subject: Re: Safe cheap objects for Modula 3

>>>>> On 26 Feb 92 19:20:51 GMT, Hans_Boehm.PARC@xerox.com said:

Hans> Let's keep things in perspective.  There is a significant cost to
Hans> allocating collectible storage rather than stack allocating storage.
Hans> [...]  You may need some locking or synchronization on allocation, or
Hans> risk fragmenting the heap by dividing it up on a per thread basis.

What I had in mind for gm3 was a generational heap where each thread has its
own nursery but the older spaces are shared. One then needs synchronization
only on scavenging and promotion, which require coordination anyway. I'd be
interested in folks thoughts on this approach (not on generational vs. other
schemes, but this multi-thread generational scheme).

I'd like to explore the optimization of stack allocation of some objects, and
in fact have a pending grant proposal on gc that would include that as part of
a comprehensive gc system. I agree that stack allocation is cheaper than heap
allocation, but I want to get some numbers that show the difference. Maybe gm3
will be running well enough soon that we can try some tests to see the
difference in cost with our collector.
--

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


======================================================================== 57 ===
Date:    Thu, 27 Feb 1992 14:12:13 PST
From:    Hans_Boehm.PARC@xerox.com
Subject: Re: SRC M3 implementation of exceptions

The rationale of the ANSI C standard states

"In fact, the only reliable way to ensure that a local variable retain (sic)
the value it had at the time of the call to longjmp is to define it with the
volatile attribute."

Unfortunately, the bundled Sun C compiler doesn't understand volatile.  But
both gcc and the unbundled compiler do, I believe.

If all else fails, you could presumably insert a

# define volatile

and be back to where you started.

I think the real cost of either this proposal is that forcing variables into
memory is expensive, so it would have to be done judiciously.

Hans


======================================================================== 58 ===
Date:    Fri, 28 Feb 1992 11:09:53 PST
From:    Hans_Boehm.PARC@xerox.com
Subject: Re: SRC M3 implementation of exceptions

That's what I meant.  I was quoting from section 4.6.2.1 of the ANSI C standard
and rationale.  (I just finished a net discussion about longjmp, malloc, and
signals.  That's why I happen to know about that section.  I agree that this
use of volatile doesn't seem to have much to do with its main purpose.)

Hans


======================================================================== 59 ===
Date:    Fri, 28 Feb 92 13:49:47 -0500
From:    Norman Ramsey <nr@Princeton.EDU>
Subject: Re: SRC M3 implementation of exceptions

Hans_Boehm.PARC@xerox.com writes...

> The rationale of the ANSI C standard states
> 
> "In fact, the only reliable way to ensure that a local variable retain (sic)
> the value it had at the time of the call to longjmp is to define it with the
> volatile attribute."

drh@princeton.edu (Dave Hanson) writes...

> there's no such stipulation in the standard that
> i can find. basically, all volatile does is prohibit
> caching, e.g.,
> 
> 	volatile int x;
> 	x = 2;
> 	y = x;
> 
> 2 must be stored in x and fetched again. the compiler
> is not allowed to avoid the fetch or delay the store.

Hans_Boehm.PARC@xerox.com writes...

> I think the real cost of either this proposal is that forcing variables into
> memory is expensive, so it would have to be done judiciously.

It is expensive, but putting the variables in registers violates the
semantics of Modula-3, which isn't any good.  In the construct
 
  TRY
    mumble
  EXCEPT
    foo
  END;

then x can be allocated to a register unless mumble sets x and foo
reads x.  Is this what you had in mind when you said `judiciously'?


Norman Ramsey
nr@princeton.edu


======================================================================== 60 ===
Date:    28 Feb 92 23:15:42 GMT
From:    chased@rbbb.Eng.Sun.COM (David Chase)
Subject: Re: SRC M3 implementation of exceptions

A couple of clarifications on what volatile does, must do, and does
not do:

1) I believe the standard allows a volatile register variable, though
I know of no such implementation.

2) Sun's C compilers, certainly, and I believe others as well, get
sufficiently paranoid when they see "setjmp" that no volatile
declarations should be necessary.  This is also a consequence of the
parameter passing standard for floating point numbers, the standard
calling sequence, and implementation of setjmp and longjmp.  (We
suffer a fair amount of casual bashing for our calling conventions --
we ought to get some benefit out of them.  NB "setjmp.h" must be
included, else the magic words are not uttered and setjmp is just
another function.)

3) The ANSI specification for volatile is pretty useless.  It doesn't
require any multiprocessor synchronization, since C (in the standard)
is a single-threaded language, and (in particular) "sequence points"
are defined with respect to a single thread of execution.  Also, a
careful reading of the standard will indicate that volatile accesses
can be reordered with respect to other accesses, as long as those
other accesses are not also volatile (page 9, ANSI C standard,
beginning "The least requirements on a conforming implementation
are").

Most likely, the barrier instructions will end up embedded within
POSIX compliant thread libraries.  Last I checked, they said all the
right words about unguarded concurrent access to shared variables.
If your C compiler emits memory barrier instructions, that's ok, but
mighty conservative.

David Chase
Sun


======================================================================== 61 ===
Date:    Fri, 28 Feb 92 15:02:51 EST
From:    Dave Hanson <drh@orchard.Princeton.EDU>
Subject: SRC M3 implementation of exceptions

   Date: Fri, 28 Feb 92 13:49:47 -0500
   From: Norman Ramsey <nr>

   Hans_Boehm.PARC@xerox.com writes...

   > The rationale of the ANSI C standard states
   > 
   > "In fact, the only reliable way to ensure that a local variable retain (si
c)
   > the value it had at the time of the call to longjmp is to define it with t
he
   > volatile attribute."

   drh@princeton.edu (Dave Hanson) writes...

   > there's no such stipulation in the standard that
   > i can find. basically, all volatile does is prohibit
   > caching, e.g.,
   > 
   > 	volatile int x;
   > 	x = 2;
   > 	y = x;
   > 
   > 2 must be stored in x and fetched again. the compiler
   > is not allowed to avoid the fetch or delay the store.

insufficient quote!
what I said was that there's no stipulation in the ANSI
standard against using registers to volatile variables.
it's OK for an implementation can put volatile variables in
registers if it retains its value at the time of a longjmp.

I think Hans's interpretation of sec. 4.6.2.1 is correct...


======================================================================== 62 ===
Date:    Fri, 28 Feb 1992 20:39:29 GMT
From:    prj@gamba.lcs.mit.edu (Paul R. Johnson)
Subject: Re: SRC M3 implementation of exceptions

Sorry, I spoke too soon and was thinking CLU exception semantics rather
than Modula-3.  In CLU the construct

  begin
    mumble
  end
    except when Exception:
                foo
    end
  bar

would, if the signal Exception were raised in mumble, execute foo and
then (unless foo returned or signaled) continue on with bar.  Personally
I prefer this to Modula-3's exception semantics as it makes exceptions
signaled by a procedure simply an alternatve form of return.  This is
often useful to handle expected (i.e., not badly exceptional) but non-normal
cases such as "end-of-file" or "not-found".

---Paul Johnson



======================================================================== 63 ===
Date:    Fri, 28 Feb 92 12:00:58 PST
From:    <swart@src.dec.com>
Subject: Re: SRC M3 implementation of exceptions


A cost of using volatile rather than the implementation dependent hack
that Norm suggests is that accessing a volatile variable acts as a
memory barrier for all variables.  That means that on a multiprocessor
special instructions have to be issued in order to flush write behind
and invalidate noncoherent read caches.

Garret


======================================================================== 64 ===
Date:    Fri, 28 Feb 1992 12:51:04 PST
From:    Hans_Boehm.PARC@xerox.com
Subject: Re: SRC M3 implementation of exceptions

"A cost of using volatile rather than the implementation dependent hack
that Norm suggests is that accessing a volatile variable acts as a
memory barrier for all variables.  That means that on a multiprocessor
special instructions have to be issued in order to flush write behind
and invalidate noncoherent read caches."

This is clearly true for volatile "extern" or "static" variables.  But those
aren't the problem.  I agree with Dave Hanson that there doesn't appear to be
any rule against putting local volatile variables in registers.  Similarly, I'm
not sure that there are any restrictions (other than the desirable one on
longjmp behavior) on what the compiler is allowed to do with volatile stack
allocated variables whose address is never taken.  Such variables presumably
can't be seen by a signal handler or another process.  I'm not terribly
confident of this interpretation, though.

On the other hand, my impression is that you are correct as far as the behavior
of current compilers is concerned.  Volatile does seem to force similar
treatments for local and nonlocal variables, even on SPARCs, where longjmp
doesn't restore old register values.

Hans


======================================================================== 65 ===
Date:    28 Feb 92 20:27:18 GMT
From:    prj@gamba.lcs.mit.edu (Paul R. Johnson)
Subject: Re: SRC M3 implementation of exceptions

nr@princeton.edu (Norman Ramsey) writes...

>It is expensive, but putting the variables in registers violates the
>semantics of Modula-3, which isn't any good.  In the construct
> 
>  TRY
>    mumble
>  EXCEPT
>    foo
>  END;
>
>then x can be allocated to a register unless mumble sets x and foo
>reads x.  Is this what you had in mind when you said `judiciously'?

In fact, I believe, in the construct

  TRY
    mumble
  EXCEPT
    foo
  END;
  bar

then x can be allocated to a register unless mumble sets x and
foo OR bar reads x.

---Paul Johnson


======================================================================== 66 ===
Date:    29 Feb 92 04:36:44 GMT
From:    moss@cs.umass.edu (Eliot Moss)
Subject: Re: SRC M3 implementation of exceptions

By the way, pursuant to the discussion of the correct implementation of
exception w.r.t. variables allocated to registers, gm3 "does the right thing".
It will restore the register contents for a variable globally (i.e., across
multiple basic blocks) allocated to a register. It does this by (a) allowing
such variables to be allocated only to callee saved registers and (b) going
through each procedure's return sequence so that callee saved registers are
restored. (This works in the raising procedure because a RAISE is a call to a
run-time routine.) The unwinding happens by changing return addresses; the
correct return address is found using a compiler generated table. This is all
operatoinal now. The one thing we do not support is restoration of caller
saved registers (gcc's scheme for that is a pain for our use and would require
reworking or else would result in rather large tables, etc.). Just thought
folks would like to know that we think about such things ....     Eliot
--

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


