home *** CD-ROM | disk | FTP | other *** search
/ ftp.pasteur.org/FAQ/ / ftp-pasteur-org-FAQ.zip / FAQ / Modula-3-faq < prev    next >
Text File  |  2002-05-03  |  61KB  |  1,340 lines

  1. Path: senator-bedfellow.mit.edu!bloom-beacon.mit.edu!howland.erols.net!sunqbc.risq.qc.ca!carnaval.risq.qc.ca.POSTED!not-for-mail
  2. From: Michel Dagenais <michel.dagenais@polymtl.ca>
  3. Newsgroups: comp.lang.modula3,news.answers,comp.answers
  4. Subject: Modula-3 Frequently Asked Questions (FAQ)
  5. Supersedes: <m3_1017756600@vlsi.polymtl.ca>
  6. Followup-To: comp.lang.modula3
  7. Organization: Ecole Polytechnique de Montreal
  8. Lines: 1322
  9. Sender: dagenais@m3.polymtl.ca
  10. Approved: news-answers-request@MIT.Edu
  11. Expires: 15 Jun 2002 13:10:00 GMT
  12. Message-ID: <m3_1020345000@vlsi.polymtl.ca>
  13. Date: Thu, 02 May 2002 12:51:37 GMT
  14. NNTP-Posting-Host: 132.207.4.60
  15. X-Trace: carnaval.risq.qc.ca 1020343897 132.207.4.60 (Thu, 02 May 2002 08:51:37 EDT)
  16. NNTP-Posting-Date: Thu, 02 May 2002 08:51:37 EDT
  17. Xref: senator-bedfellow.mit.edu comp.lang.modula3:12299 news.answers:229479 comp.answers:49803
  18.  
  19. Archive-name: Modula-3-faq
  20.  
  21.    Michel Dagenais Michel Dagenais, GNU General Public License, 1998-2001
  22.    
  23.    
  24.     michel.dagenais@polymtl.ca
  25.     Ecole Polytechnique
  26.     C.P. 6079, Succ. Centre-Ville
  27.     Montreal, Quebec, H3C 3A7
  28.     
  29.                 Modula-3 Frequently asked questions and answers
  30.                                        
  31.    Maintained by Michel Dagenais ([1]michel.dagenais@polymtl.ca),
  32.    suggestions are most welcome. Last updated January 15 2002. The latest
  33.    copy of this FAQ may be obtained from the [2]Polytechnique Montreal
  34.    Modula-3 Home.
  35.    
  36. Introduction
  37.  
  38. What is Modula-3?
  39.  
  40.    Modula-3 is a systems programming language that descends from Mesa,
  41.    Modula-2, Cedar, and Modula-2+. It also resembles its cousins Object
  42.    Pascal, Oberon, and Euclid.
  43.    
  44.    The goal of Modula-3 is to be as simple and safe as it can be while
  45.    meeting the needs of modern systems programmers. Instead of exploring
  46.    new features, we studied the features of the Modula family of
  47.    languages that have proven themselves in practice and tried to
  48.    simplify them into a harmonious language. We found that most of the
  49.    successful features were aimed at one of two main goals: greater
  50.    robustness, and a simpler, more systematic type system.
  51.    
  52.    Modula-3 retains one of Modula-2's most successful features, the
  53.    provision for explicit interfaces between modules. It adds objects and
  54.    classes, exception handling, garbage collection, lightweight processes
  55.    (or threads), and the isolation of unsafe features.
  56.    
  57. Where is Modula-3 used? Is it used in industry?
  58.  
  59.    A number of programming teams selected Modula-3 for industrial and
  60.    research projects, and for teaching. It encourages good programming
  61.    practices and comes with excellent libraries for distributed
  62.    programming and graphical user interfaces. A non exhaustive list is
  63.    available at [3][Modula-3 at Work].
  64.    
  65. Is commercial support available?
  66.  
  67.    Critical Mass Corporation used to offer their own version of SRC
  68.    Modula-3, CM3, an integrated development environment for Modula-3,
  69.    [4]Reactor, as well as training and consulting services.
  70.    
  71.    Olaf Wagner from [5]Elego Software Solutions is now maintaining [6]CM3
  72.    as an open source package and offers commercial support.
  73.    
  74. Where can I get documents and information on Modula-3?
  75.  
  76.    A [7]concise bibliography and a more complete [8]bibliography describe
  77.    Modula-3 related books, technical reports, and papers. The definition
  78.    of Modula-3 is contained in: [9]"System Programming with Modula-3"
  79.    also known as SPwM3. Sam Harbison has written a more tutorial book
  80.    titled [10]Modula3.
  81.    
  82.    Three main Web servers contain Modula-3 related information:
  83.    [11]www.m3.org, [12]DEC SRC Modula-3 home page, and [13]Ecole
  84.    Polytechnique de MontrΘ Modula-3 home page.
  85.    
  86.    The Usenet newsgroup comp.lang.modula3 is the official meeting place
  87.    for Modula-3 related discussions.
  88.    
  89. Is Modula-3 a superset of Modula-2?
  90.  
  91.    No; valid Modula-2 programs are not valid Modula-3 programs. However,
  92.    there is a tool to help convert Modula-2 programs to Modula-3.
  93.    
  94. Comparisons between Modula-3 and other languages?
  95.  
  96.    From: laszlo@post.ifi.uni-klu.ac.at (Laszlo BOESZOERMENYI)
  97.    
  98.    A Comparison of Modula-3 and Oberon-2 by myself in Structured
  99.    Programming 1993, 14:15-22
  100.    
  101.    From: nayeri@gte.com
  102.    
  103.    Robert Henderson, Benjamin Zorn, A Comparison of Object-Oriented
  104.    Programming in Four Modern Languages, Department of Computer Science,
  105.    University of Colorado, Boulder, Colorado, [14]Technical Report
  106.    CU-CS-641-93.
  107.    
  108.    The paper evaluates Oberon, Modula-3, Sather, and Self in the context
  109.    of object-oriented programming. While each of these programming
  110.    languages provide support for classes with inheritance, dynamic
  111.    dispatch, code reuse, and information hiding, they do so in very
  112.    different ways and with varying levels of efficiency and simplicity. A
  113.    single application was coded in each language and the experience
  114.    gained forms the foundation on which the subjective critique is based.
  115.    
  116. What implementations are available, how do they compare?
  117.  
  118.    All implementations are based on [15]DEC SRC Modula-3. [16]Critical
  119.    Mass offered an improved version with commercial support. It features
  120.    incremental garbage collection on NT, and a few additional packages
  121.    like ODBC database access. This is now [17]open sourced and maintained
  122.    by Olaf Wagner. Ecole Polytechnique de MontrΘal has been maintaining
  123.    an [18]updated distribution. It features integrated documentation, and
  124.    NT support through the gcc cygwin compiler
  125.    
  126. Can I contribute Modula-3 software?
  127.  
  128.    Contributions are most welcome. The primary contact to offer
  129.    contributions is comp.lang.modula3.
  130.    
  131.    [19]The Ecole Polytechnique de MontrΘal Modula-3 distribution is the
  132.    most regularly updated and may be a good place to submit your
  133.    contribution.
  134.    
  135. Why use Modula-3?
  136.  
  137.    Here is what John Polstra, author of the popular CVSup, replied:
  138. Subject: Re: SUP on sup.freebsd.org
  139. Date:Wed, 06 Nov 1996 12:31:26 -0800
  140. From:John Polstra
  141. > Erhm, why on earth did you chose Modula3 ??
  142.  
  143.    Modula-3 really is a different language, designed specifically for
  144.    systems programming by some extremely competent and experienced people
  145.    who knew what they were doing.
  146. > Oh and yes I have seen apps written in modula3, all of which was
  147. > horrible performers, and impossible to port to new platforms, so
  148. > the management decide a complete rewrite in, guess what, C!
  149.  
  150.    Are you sure it was Modula-3? The SRC Modula-3 compiler supports about
  151.    25 different platforms.
  152.    
  153.    Plenty of real world apps (*big* ones) have been written in Modula-3,
  154.    and they perform pretty well. There's also the SPIN OS project
  155.    [20][SPIN] at University of Washington, in which the kernel was
  156.    written in Modula-3. It performs well, too.
  157.    
  158.    Now, you can always argue that a program would be somewhat faster and
  159.    somewhat smaller if it had been written in C. Hey, guess what? I was
  160.    around when Unix V6 came out, and the same stuff was written about it.
  161.    Just substitute "C" for "Modula-3" and "assembly language" for "C".
  162.    The answer is the same in both cases: Unix would not exist as we know
  163.    it today if it had been written in assembly language. CVSup would not
  164.    exist as we know it today if it had been written in C (or C++, for
  165.    that matter).
  166.    
  167.    OK, so why on earth did I choose Modula-3? In no particular order:
  168.     1. I needed application level threads, and threads are an integral
  169.        part of the Modula-3 language. About the only reasonable
  170.        alternative was to use pthreads with C or C++. But pthreads was
  171.        not well supported under FreeBSD at that time.
  172.     2. I needed a graphical display during development so that I could
  173.        monitor the 3 client threads as they were running, debug them,
  174.        appraise their relative performance, and find the bottlenecks.
  175.        Modula-3 has a very nice toolkit for creating GUIs quickly and
  176.        painlessly. (OK, so the scrollbars are as ugly as sin.)
  177.     3. Modula-3 is a compiled language that is reasonably efficient.
  178.     4. I needed to use some low level system functions, e.g., mapping
  179.        files into memory. Modula-3 provides good access to such
  180.        functions, and it is quite easy to add interfaces to foreign
  181.        libraries such as "libz".
  182.     5. Modula-3 has good support for networking.
  183.     6. It is a mature and stable language that has been used in a number
  184.        of serious, large projects. The language and compiler have been
  185.        stable for about 5 years, which is more than you can say for C++.
  186.     7. It has nice support for object oriented programming, including a
  187.        good type system, a nice exception model, and a modern
  188.        high-performance garbage collector. These traits, IMHO, contribute
  189.        powerfully to producing well-structured, maintainable programs.
  190.        Now before you label me an unstudly OO weenie, please consider
  191.        this. I've been programming in C professionally for 19 years. I
  192.        made my living for many years writing C compilers and related
  193.        tools such as assemblers, linkers, and disassemblers. I still use
  194.        C and C++ when I feel they are appropriate for a project, not to
  195.        mention when I have to because that's what the client wants to
  196.        use. I have experience programming in many many different
  197.        languages. Different languages are good for different things. I
  198.        still like programming in C (and C++ for some things), but I'm
  199.        glad I didn't use it for CVSup.
  200.     8. I had just come off a huge 3+ year C++ project. During that time,
  201.        I learned just how much C++ sucks. I did not feel like doing it
  202.        again right away "for fun."
  203.     9. I have spent my entire professional career getting paid to use the
  204.        wrong tools, because, e.g., the manager read that C++ was
  205.        "popular." For once, just once, on a _hobby_ project, I decided I
  206.        was going to use the tool I felt was the best for the job at hand.
  207.        I thought about it long and hard, evaluated several options (C and
  208.        C++ among them), and eventually chose Modula-3. I have never
  209.        regretted that decision.
  210.        
  211.    Any questions? :-)
  212. John
  213. - --
  214.    John Polstra                                       jdp@polstra.com
  215.    John D. Polstra & Co., Inc.                Seattle, Washington USA
  216.    "Self-knowledge is always bad news."                 -- John Barth
  217.  
  218. Troubleshooting
  219.  
  220. Why program receives a SEGV signal under the debugger?
  221.  
  222.    The garbage collector on some platforms uses the SEGV (segmentation
  223.    violation) signal to detect modified portions of the dynamically
  224.    allocated space. It is possible to disable this feature or to inform
  225.    the debugger to let these signals propagate. See the [21]m3gdb
  226.    documentation.
  227.    
  228. Problems with threads, fork and VTALARM?
  229.  
  230.    The threads are implemented using the virtual timer interrupt.
  231.    Normally, the run time environment will catch the interrupt and
  232.    determine if thread switching is appropriate. However, if a new
  233.    process is created with fork, it will have the virtual timer activated
  234.    and no interrupt handler to receive it, resulting in a core dump. If
  235.    you use the standard procedure Process.Create to fork new processes,
  236.    this will be handled automatically for you. If you insist on using
  237.    fork, you need to disable the timer, fork and then reenable the timer.
  238.    
  239. X libraries not found?
  240.  
  241.    The position of X libraries is stored, for instance for pre-compiled
  242.    PM3 LINUXELF binaries, in the template file m3config/src/LINUXELF as
  243.    well as in X11/LINUXELF/.M3EXPORTS (m3build/templates/LINUXELF, and
  244.    X11R4/LINUXELF/.M3EXPORTS for SRC-M3). Thus you may want to edit these
  245.    files if your X libraries are located in an uncommon place.
  246.    
  247. What means Missing RTHooks or similar messages?
  248.  
  249.    The standard library, libm3, is not included by default. You need in
  250.    your m3makefiles to import("libm3") or to import a library which
  251.    imports libm3. Otherwise, messages about run time procedures such as
  252.    RTHooks not being available are produced.
  253.    
  254. M3build versus Make or why m3 does not work?
  255.  
  256.    The Modula-3 compiler m3 does a much finer grained dependency analysis
  257.    than possible with make. For this reason, a very flexible front end,
  258.    m3build, reads the program description files, m3makefile, and
  259.    generates the commands required to compile and link Modula-3 programs
  260.    and libraries. The m3makefile content is documented in the m3build
  261.    documentation. Calling the m3 compiler directly is difficult and thus
  262.    not recommended, especially on PM3 where it is now merged with
  263.    m3build.
  264.    
  265. Why are exceptions raised by X or Network Objects applications?
  266.  
  267.    Graphical applications (based on Trestle/X Windows) raise the
  268.    TrestleComm.Failure exception when the DISPLAY environment variable is
  269.    incorrect or the X server is refusing the connection. They raise
  270.    MachineIDPosix.Failure if the network configuration files are
  271.    incorrectly set up, especially on LINUX; /etc/hosts must contain at
  272.    least a loopback address (127.0.0.1) and the /etc/rc scripts an
  273.    appropriate ifconfig command (/etc/ifconfig lo 127.0.0.1; /etc/route
  274.    add 127.0.0.1). Applications with Network Objects may also raise
  275.    exceptions or consume all the CPU time available when the network
  276.    configuration files are incorrect.
  277.    
  278. What is the story with Trestle and OpenWindows?
  279.  
  280.    Mark Manasse says:
  281.    
  282.    I think that the OpenWindows release should be enough (no need to get
  283.    the MIT X release), although there are a few things in Trestle that
  284.    trigger devastating bugs in OpenWindows. But the only library we
  285.    depend on is Xlib, R4 or later.
  286.    
  287.    The main thing I know that crashes OW 2.0 is the code where we call
  288.    GrabKey specifying AnyKey. You can either loop over all of the keys,
  289.    or you can just comment out the call; programs won't run exactly the
  290.    same, but you probably won't notice the difference.
  291.    
  292. Why so many problems installing on Solaris?
  293.  
  294.    These notes were contributed by (simon.hood@umist.ac.uk) while
  295.    installing PM3-1.1.14 on a Sun Ultra 5 running Solaris 2.8. They
  296.    describe various problems and their solution or workaround.
  297.    
  298.    The installation of PM3 on Solaris systems is particularly prone to
  299.    problems as these systems tend to be an unpredictable (from the point
  300.    of view of the PM3 people) mixture of Sun and Gnu software --- Sun do
  301.    not bundle a C compiler with the operating system.
  302.    
  303.    My machine has gcc version 2.95.2 installed; it has Sun's versions of
  304.    make, ld, as and ar installed within /usr/ccs/bin; Gnu's version of
  305.    these tools are not installed.
  306.    
  307.    My installation was successful, after a bit of fiddling around with
  308.    the configuration/template files and environment variables. Some of
  309.    the fixes are trivial (if you know what you are doing), while others
  310.    --- for me at least --- were not --- I am a Modula 3 novice and far
  311.    from experienced with Solaris.
  312.    
  313.    The issues that arose are:
  314.      * Paths needed to be set to find tools such as make.
  315.      * LD_LIBRARY_PATH needed to be set to ensure libstdc++.a.2.10.0
  316.        and/or libstdc++.so.2.10.0 were found.
  317.      * A link needed to be set so that byacc points to yacc.
  318.      * The configuration for linking needed to be changed since only the
  319.        Sun version of ld was installed, not Gnu's.
  320.      * The build of m3gdb failed to build.
  321.      * The gnuemacs package failed to build.
  322.        
  323. Initial Problems
  324.  
  325.    Paths
  326.           gcc is usually installed in /usr/local/bin; on a Solaris
  327.           machine, ar, as, make and ld are all in /usr/ccs/bin, by
  328.           default. Hence these must both be on root's path (assuming you
  329.           are installing as root). Neither were; I have not changed any
  330.           paths since installation of Solaris 2.8 on a new machine a few
  331.           days ago.
  332.           This is in addition to /usr/local/pm3/bin, as mentioned by the
  333.           PM3 installation instructions.
  334.           
  335.    byacc/yacc
  336.           The build required byacc. yacc is installed in /usr/ccs/bin; a
  337.           soft link:
  338.           
  339.      lrwxrwxrwx   1 root     other          4 Aug 11 15:45 byacc -> yacc
  340.  
  341.  
  342.           solved this problem.
  343.           
  344.    Library Paths
  345.           In addition to /usr/local/pm3/lib/m3 as mentioned by the PM3
  346.           installation instructions LD_LIBRARY_PATH must include
  347.           /usr/local/lib so that libstdc++ (part of the gcc distribution)
  348.           can be found.
  349.           
  350.    CC
  351.           In addition I found that the environment variable CC needed to
  352.           be set to /usr/local/bin/gcc. This is of course mentioned in
  353.           the PM3 installation instructions.
  354.           
  355. Miscellaneous Questions
  356.  
  357. Can I get Modula-3 other than by FTP or HTTP?
  358.  
  359.    Prime Time Freeware (PTF) includes Modula-3. PTF is a set of two
  360.    ISO-9660 CDroms filled with 3GB of freeware, issued semi-annually. PTF
  361.    is distributed via bookstores and mail. You can reach PTF using:
  362.    
  363.         Email:  ptf@cfcl.com
  364.         Fax:    [1] (408) 738 2050
  365.         Voice:  [1] (408) 738 4832
  366.         Mail:   Prime Time Freeware
  367.                 415-112 N. Mary Ave., Suite 50
  368.                 Sunnyvale, CA 94086
  369.                 USA
  370.  
  371.    Many Linux CDroms include a copy of the FTP site tsx-11.mit.edu which
  372.    has Linux binaries for Modula-3.
  373.    
  374. How to call Modula-3 procedures from a C program?
  375.  
  376.    Calling Modula-3 from C is tricky because M3 has a more elaborate
  377.    run-time environment. The simplest solution is to make the main
  378.    program M3 and then call C via EXTERNAL routines. Calling back into M3
  379.    is then relatively straightforward.
  380.    
  381.    Here's an example. It calls the C code to lodge the identity of the M3
  382.    procedure to be called back which avoids having to know the actual
  383.    name used by the linker.
  384.    
  385.    First a little M3 module to be called from C (M3code), then a C module
  386.    called by the M3 main and calling the M3 module (Ccode), and finally
  387.    the main program (Main):
  388. (* M3code.i3 *)
  389.  
  390. INTERFACE M3code;
  391. IMPORT Ctypes;
  392. PROCEDURE put (a: Ctypes.char_star);
  393. END M3code.
  394.  
  395. (* M3code.m3 *)
  396.  
  397. UNSAFE MODULE M3code;
  398. IMPORT Ctypes, IO, M3toC;
  399.  
  400. PROCEDURE put (a: Ctypes.char_star) =
  401.   BEGIN
  402.     IO.Put (M3toC.StoT (a) & "\n");
  403.   END put;
  404.  
  405. BEGIN
  406. END M3code.
  407.  
  408. (* Ccode.i3 *)
  409.  
  410. <*EXTERNAL*> INTERFACE Ccode;
  411. IMPORT Ctypes;
  412. PROCEDURE set (p: PROCEDURE (a: Ctypes.char_star));
  413. PROCEDURE act (a: Ctypes.char_star);
  414. END Ccode.
  415.  
  416. /* Ccode.c */
  417.  
  418. typedef void (*PROC)();
  419. static PROC action;
  420.  
  421. void set (p)
  422.   PROC p;
  423.   {
  424.     action = p; /* register the M3 procedure */
  425.   }
  426.  
  427. void act (a)
  428.   char *a;
  429.   {
  430.     action (a); /* call the M3 procedure */
  431.   };
  432.  
  433. (* Main.m3 *)
  434.  
  435. UNSAFE MODULE Main;
  436.  
  437. IMPORT Ccode, M3code, M3toC;
  438.  
  439. BEGIN
  440.   Ccode.set (M3code.put);
  441.   Ccode.act (M3toC.TtoS ("Hello world"));
  442. END Main.
  443.  
  444. (* m3makefile *)
  445.  
  446. import(libm3)
  447.  
  448. interface ("Ccode")
  449. c_source ("Ccode")
  450. module ("M3code")
  451. implementation("Main")
  452. program("mixed")
  453.  
  454. Can Modula-3 code call C++ and vice-versa?
  455.  
  456.    There is no problem to call C++ functions declared as extern C. You
  457.    must use a C++ aware linker (e.g. the C++ compiler). A complete
  458.    example of M3 calling C++ objects, which in turn call M3 callbacks, is
  459.    available in [22]the sgml library.
  460.    
  461.    On some platforms, a call to get the static variables constructors
  462.    called may be required:
  463.    
  464.    From: gwyant@cloyd.East.Sun.COM (Geoffrey Wyant - Sun Microsystems
  465.    Labs BOS)
  466.    
  467.    You must use your C++ compiler as the linker, rather than /bin/cc or
  468.    /bin/ld.
  469.    
  470.    You need to call the function '_main'. The easiest way to do this is
  471.    to have the following set of interfaces and implementations:
  472.    
  473.         INTERFACE CXXMain;
  474.           <*EXTERN "_main"*> CxxMain;
  475.         END CXXMain;
  476.  
  477.         MODULE CXXMain;
  478.         BEGIN
  479.           CxxMain();
  480.         END;
  481.  
  482.    and then import CXXMain into your M3 main module. This will ensure
  483.    that the C++ function _main gets called.
  484.    
  485. How to copy heap objects?
  486.  
  487.    Deep copies are easily performed using Pickles. An object graph is
  488.    Pickled to a text writer into a TEXT. Then, a copy is created by
  489.    unpickling a new object graph from a text reader created from the
  490.    TEXT.
  491.    
  492.    Shallow copies are less often needed but may be performed with the
  493.    following procedure:
  494. PROCEDURE Duplicate (r: REFANY): REFANY =
  495.   VAR
  496.     tc     := TYPECODE (r);
  497.     n_dims : INTEGER;
  498.     res    : REFANY;
  499.     shape  : RTHeapRep.ArrayShape;
  500.   BEGIN
  501.     IF (r = NIL) THEN RETURN NIL END;
  502.  
  503.     (* allocate a new object of the same type (and shape) as the old one *)
  504.     RTHeapRep.UnsafeGetShape (r, n_dims, shape);
  505.     IF (n_dims <= 0)
  506.       THEN res := RTAllocator.NewTraced (tc);
  507.       ELSE res := RTAllocator.NewTracedArray (tc, SUBARRAY(shape^, 0, n_dims));
  508.     END;
  509.  
  510.     (* copy the old data into the new object *)
  511.     RTMisc.Copy (RTHeap.GetDataAdr (r), RTHeap.GetDataAdr (res),
  512.                  RTHeap.GetDataSize (r));
  513.  
  514.     RETURN res;
  515.   END Duplicate;
  516.  
  517. How to get output messages to appear immediately (flushing writers)?
  518.  
  519.    Modula-3 Writers are buffered. Thus, you need to issue a Wr.Flush when
  520.    the output should appear immediately, for instance to prompt the user
  521.    for some input. Since this can become annoying, libraries in other
  522.    languages sometimes offer the option of unbuffered writes. In
  523.    Modula-3, an equivalent behavior is obtained with AutoFlushWr which
  524.    gets a background thread to flush a writer at a specified interval.
  525.    
  526. How to read a single character as soon as typed?
  527.  
  528.    Characters typed on the keyboard are usually buffered. They become
  529.    visible to the reading program only when the buffer is full or after,
  530.    for example, a carriage return is received. This is not specific to
  531.    Modula-3. To access the characters as they are typed, single character
  532.    commands in a full screen editor for example, the input reader must be
  533.    configured properly.
  534.    
  535.    From: [23]rrw1000@cus.cam.ac.uk (Richard Watts)
  536.    
  537.    The POSIX way of doing it is to use tcsetattr(), and here is some code
  538.    that does it under Solaris 2.x (this was written for serial ports, but
  539.    the same thing applies) :
  540. PROCEDURE Open(port : CHAR; timeout : INTEGER := 30) : T RAISES {Error} =
  541.   VAR
  542.     term : TcPosix.termios;
  543.     file : TEXT;
  544.     fd : T;
  545.     rc : INTEGER;
  546.   BEGIN
  547.     (* Figure out which device we want to open : *)
  548.  
  549.     CASE port OF
  550.       'A' => file := "/dev/ttya";
  551.     | 'B' => file := "/dev/ttyb";
  552.     ELSE RAISE Error("Invalid port " & Fmt.Char(port) & " specified.\n");
  553.     END;
  554.  
  555.     (* Open it. 700 is a good default mode for serial ports. *)
  556.     fd := Unix.open(M3toC.TtoS(file),  Unix.O_RDWR
  557.                                             , 8_700);
  558.     IF fd = -1 THEN
  559.       RAISE Error("Open() on " & file & " failed.\n");
  560.     END;
  561.  
  562.     (* Get the termios structure for it *)
  563.     rc := TcPosix.tcgetattr(fd, ADR(term));
  564.     IF rc # 0 THEN
  565.       EVAL Unix.close(fd);
  566.       RAISE Error("Couldn't get terminal attributes for " & file & ".\n");
  567.     END;
  568.  
  569.     (* Modify the termios structure *)
  570.  
  571.     (* The default baud rate is right, but we'd better set it anyway
  572.        in case someone left it set up wrong : *)
  573.     rc := TcPosix.cfsetospeed(ADR(term), TcPosix.B9600);
  574.  
  575.     IF rc # 0 THEN
  576.       EVAL Unix.close(fd);
  577.       RAISE Error("Couldn't set output speed for " & file & "\n");
  578.     END;
  579.  
  580.     rc := TcPosix.cfsetispeed(ADR(term), TcPosix.B9600);
  581.  
  582.     IF rc # 0 THEN
  583.       EVAL Unix.close(fd);
  584.       RAISE Error("Couldn't set input speed for " & file & "\n");
  585.     END;
  586.  
  587.     (* Modify the line discipline - reset ECHO and ICANON *)
  588.     term.c_lflag := Word.And( term.c_lflag,
  589.                               Word.Not(
  590.                                   Word.Or(TcPosix.ICANON,
  591.                                           TcPosix.ECHO)));
  592.     term.c_cc[TcPosix.VMIN] := 0;
  593.     term.c_cc[TcPosix.VTIME] := 0; (* Set up timing right *)
  594.  
  595.     (* Now reset the terminal attributes *)
  596.     rc := TcPosix.tcsetattr(fd, TcPosix.TCSANOW, ADR(term));
  597.  
  598.     IF rc # 0 THEN
  599.       EVAL Unix.close(fd);
  600.       RAISE Error("Can't set attributes for " & file & "\n");
  601.     END;
  602.     RETURN fd;
  603.   END Open;
  604.  
  605.    (TcPosix.i3 is one of my interfaces, not libm3's, and I'll supply it
  606.    if you like, but it's just a wrapper to tcgetattr and friends. The
  607.    baud rate stuff shouldn't be necessary for terminals (or serial
  608.    ports..) ). You should be able to somehow get an Rd.T out of this, I
  609.    think, but it may involve a bit of hacking. The University of
  610.    Cambridge can't have these opinions even if it wants them.
  611.    
  612. Why is Hello World larger in Modula-3 than in C?
  613.  
  614.    Modula-3 programs are slightly larger than C programs because the
  615.    generated code includes runtime type information, and runtime checks
  616.    for out-of-bound array references and NIL pointers. Many of these
  617.    checks could be removed by a more sophisticated compiler.
  618.    
  619.    The fixed runtime is substantially larger (there is no runtime support
  620.    in C). It contains a garbage collector, a thread runtime, and
  621.    exception support. It is typically placed in a dynamically linked
  622.    library, shared on disk and in memory between all the Modula-3
  623.    programs.
  624.    
  625. What is SRC Modula-3?
  626.  
  627.    [24]SRC-Modula-3 was built by the DEC Systems Research Center and is
  628.    freely available and redistributable, with source code. In Europe it
  629.    is also available from ftp-i3.informatik.rwth-aachen.de in
  630.    pub/Modula-3. The most recent version is release 3.6
  631.    
  632.    The DEC SRC Modula-3 contains the following:
  633.    
  634.      * A native code compiler: uses the GCC backend; on
  635.        machines/operating systems that have self-describing stacks, an
  636.        optimized exception handling mechanism is provided, on other
  637.        architectures, setjmp/longjmp is used. A very fast integrated
  638.        backend is available on some platforms (currently NT386 and Linux
  639.        i386).
  640.        The compilation system provides for minimal recompilation. Only
  641.        those units that depend on the modified interface item will be
  642.        recompiled.
  643.      * m3build: tool that performs dependency analysis and builds the
  644.        Modula-3 programs and libraries.
  645.      * m3gdb: a Modula-3 aware version of GDB.
  646.      * Several tools for performance and coverage analysis.
  647.      * A large standard library (libm3) providing
  648.           + A multithread, incremental, generational, conservative
  649.             garbage collector
  650.           + Text manipulation.
  651.           + Generic Containers: Lists, Sequences, Tables, SortedLists,
  652.             SortedTables
  653.           + Atoms and Symbolic expressions (Lisp like lists)
  654.           + An extensible stream IO system
  655.           + Typesafe binary object transcription (persistent objects)
  656.           + Operating system interfaces
  657.           + Portable interfaces to the language runtime
  658.        All standard libraries are thread-friendly. Modula-3 can readily
  659.        link with existing C libraries; many libraries including X11R4 and
  660.        various UNIX libraries are available as part of libm3.
  661.      * Several other libraries for designing graphical user interfaces
  662.        and distributed applications.
  663.        
  664. Why are there strange pragmas for Locking levels and other properties?
  665.  
  666.    The Trestle (ui library) interfaces contain Locking level pragmas. The
  667.    base interfaces (libm3 library) contain SPEC pragmas. These are not
  668.    processed by the compiler. Instead the Extended Static Checker,
  669.    currently under development at DEC SRC, will report on problems
  670.    detected based on the program content and the information specified in
  671.    these pragmas [25][ESC]. The Extended Static Checker is not yet
  672.    available, it may be some time in the future.
  673.    
  674. Design Issues
  675.  
  676. Why objects and interfaces?
  677.  
  678.    Allan Heydon on comp.lang.modula3, May 4th 1993:
  679.    
  680.    Modula-3 provides two separate mechanisms for data-hiding: one for
  681.    hiding details about how interfaces are implemented, and the other for
  682.    hiding details about how objects are implemented.
  683.    
  684.    The first data-hiding mechanism is realized by the distinction between
  685.    interfaces and modules. Clients can only import interfaces, so the
  686.    names declared in the modules implementing those interfaces are hidden
  687.    from clients. Note that this mechanism has only two levels; a name is
  688.    either declared in an interface, or it isn't. If a name is only
  689.    declared in a module, it can't be used by a client.
  690.    
  691.    The second data-hiding mechanism is realized by opaque types and
  692.    revelations. A Modula-3 interface may declare an object type to be
  693.    opaque, in which case only a subset of the fields and methods of that
  694.    object are revealed to clients importing the interface. Furthermore,
  695.    the Modula-3 revelation mechanism allows a designer to reveal
  696.    successively more fields and methods of an object in a series of
  697.    interfaces. The fields and methods visible to a client then depends on
  698.    which interfaces the client imports.
  699.    
  700.    The latter mechanism is quite flexible. As opposed to the
  701.    interface/module data-hiding mechanism, opaque types allow you to
  702.    define an arbitrary number of levels at which more and more
  703.    information about the implementation of your object is revealed.
  704.    
  705.    See Sections 2.2.10, 2.4.6, and 2.4.7 of "Systems Programming with
  706.    Modula-3" for more information about opaque types and about partial
  707.    and complete revelations.
  708.    
  709. What is the purpose of BRANDED and REVEAL?
  710.  
  711.    Allan Heydon writes:
  712.    
  713.    These two keywords are necessary because of two quite different
  714.    features of the language. REVEAL is necessary because Modula-3 has
  715.    opaque types and partial revelations. BRANDED is necessary because the
  716.    Modula-3 type system uses structural equivalence instead of name
  717.    equivalence.
  718.    
  719.    In Modula-3, the concrete structure of a type can be hidden from
  720.    clients in an interface. A common idiom is:
  721.    
  722.   INTERFACE I;
  723.  
  724.   TYPE
  725.     T <: TPublic;
  726.     TPublic = OBJECT
  727.       (* fields *)
  728.     METHODS
  729.       (* methods *)
  730.     END;
  731.  
  732.   END I.
  733.  
  734.    The line "T <: TPublic" introduces the type "I.T" as an opaque subtype
  735.    of the type "I.TPublic". It does not reveal any of the other details
  736.    of the concrete structure of "I.T" to clients. Hence, "I.T" is said to
  737.    be an opaque type. Put another way, the structure of "I.T" is only
  738.    partially revealed to clients.
  739.    
  740.    In addition, it is possible to reveal more of "I.T"'s structure in
  741.    other interfaces, like this:
  742.    
  743.   INTERFACE IRep;
  744.  
  745.   IMPORT I;
  746.  
  747.   TYPE
  748.     TPrivate = I.TPublic OBJECT
  749.       (* more fields *)
  750.     METHODS
  751.       (* more methods *)
  752.     END;
  753.  
  754.   REVEAL
  755.     I.T <: TPrivate;
  756.  
  757.   END IRep.
  758.  
  759.    This interface declares a type "IRep.TPrivate" that is a subtype of
  760.    "I.TPublic". It also asserts that "I.T" is also a subtype of
  761.    "IRep.TPrivate". A client that imports only the interface "I" has
  762.    access only to the fields and methods in "I.TPublic" when accessing an
  763.    object of type "I.T", but a client that imports both "I" and "IRep"
  764.    also has access to the fields and methods in "IRep.TPrivate" when
  765.    accessing an object of type "I.T".
  766.    
  767.    The "REVEAL" statement in this module simply asserts a subtype
  768.    relation. Unlike type declarations, revelations introduce no new
  769.    names. Hence, we could not have used the "TYPE" keyword in this case
  770.    because the type "I.T" has already been declared once (albeit
  771.    opaquely) in interface "I".
  772.    
  773.    Every opaque type must have a complete revelation. A complete
  774.    revelation has the form:
  775.    
  776.   REVEAL
  777.     T = TConcrete;
  778.  
  779.    The revelation specifies that "TConcrete" is the concrete type for the
  780.    opaque type "T".
  781.    
  782.    The Modula-3 type system uses structural equivalence instead of name
  783.    equivalence. This means that two types are equal iff they have the
  784.    same structure. One consequence of this rule is that two types you
  785.    might intend to be distinct may actually be equal. This can have
  786.    unintended effects on the run-time behavior of your program. For
  787.    example, if both types that you expect to be distinct are actually
  788.    structurally equivalent and the two types guard two arms of a TYPECASE
  789.    statement, the arm for the second type will never be taken.
  790.    
  791.    If you want to avoid accidental equalities between two types, you can
  792.    brand one (or both) of them with the BRANDED keyword. A branded type
  793.    is equivalent to no other type, even if it is structurally equivalent
  794.    to some other type. In essence, the BRANDED keyword adds a bit of
  795.    virtual structure to the type that guarantees it will be distinct from
  796.    every other type.
  797.    
  798.    The Modula-3 syntax allows you to supply a text constant as a name for
  799.    the brand. If you don't supply an explicit brand, the compiler will
  800.    make one up; however, the implicit brand invented by the compiler is
  801.    not guaranteed to be chosen deterministically. Hence, explicit brands
  802.    are useful if you are communicating types from one process to another
  803.    and if you want to be sure that the branded type written by one
  804.    process matches the branded type read in by the other.
  805.    
  806.    Any two opaque types in a program must be distinct. Otherwise, it
  807.    would be too easy for clients to accidentally trip over type
  808.    collisions like the TYPECASE example mentioned above. To enforce the
  809.    restriction that all opaque types are distinct, the language requires
  810.    that the type "TConcrete" in the complete revelation above must be a
  811.    branded type.
  812.    
  813. Can a program recover from running out of virtual memory?
  814.  
  815.    No, this turns out to be quite a thorny problem. I think the best
  816.    thing I can do is by attaching to this message the dialog that went on
  817.    during the "beta test" of the new library interfaces (SRC Research
  818.    Report 113, "Some Useful Modula-3 Interfaces). The parties are Xerox
  819.    PARC's David Goldberg, Hans Boehm, Alan Demers, and David Nichols, and
  820.    SRC's John DeTreville, who designed and implemented the garbage
  821.    collector in SRC Modula-3. The dialog covers many of the issues, and
  822.    apparently ends when the participants run out of steam.
  823.    
  824.    Paul McJones mcjones@src.dec.com (editor of SRC 113)
  825.    
  826. RTAllocator should allow handling out of memory
  827.  
  828.    David Goldberg: ... there is one system problem that is not currently
  829.    handled, namely running out of memory. I would very, very much like to
  830.    see this handled in RTAllocator. One approach was suggested by Roy
  831.    Levin a while back: Have a RegisterNoMemory(proc) routine that causes
  832.    proc() to be called when memory is gone (or very low). Example of use:
  833.    in the 'Solitaire' program, the 'Hint' button generates a tree of
  834.    possible moves. If this tree gets very big and consumes all memory,
  835.    the RegisterNoMemory proc could abandon the search down the current
  836.    branch, NIL-out that branch, and ask for a garbage collection.
  837.    Currently what happens is that Solitaire crashes if you bug 'Hint' and
  838.    memory is low.
  839.    
  840.    Interface Police: Ok, make a concrete proposal and we'll talk. How low
  841.    should memory be before the runtime complains? Before or after a
  842.    collection? Is it ok to call your procedure from inside a runtime
  843.    critical section (after all, you're probably in the middle of a NEW)?
  844.    Are multiple notification procedures allowed to be registered?
  845.    Shouldn't a routine that consumes arbitrary amounts of memory be coded
  846.    to poll the allocator to ask how much memory is available?
  847.    
  848.    Hans Boehm/Alan Demers/David Goldberg/David Nichols: We believe that
  849.    programs wishing to handle allocation failures will be able to do so
  850.    with high (but not perfect) reliability if the interface provides two
  851.    features: versions of the RTAllocator.New routines that report if the
  852.    allocation is not possible (either by returning NIL or raising an
  853.    exception), and a way to register a callback when memory is low. Both
  854.    features are necessary. Here are two typical scenarios:
  855.    
  856.      * The Solitaire program. Before starting, Solitaire allocates a
  857.        'safety net' block of memory, and registers a callback. When
  858.        memory is exhausted, the callback frees the safety net, sets a
  859.        flag, and returns. In the Solitaire program proper, the inner loop
  860.        of the move generator checks the flag immediately after allocating
  861.        a new node. If the flag is set, it abandons the search. It would
  862.        not work for Solitiare to allocate new tree nodes with
  863.        RTAllocator.New() and check for an error: as memory gets low, a
  864.        library routine in some other package could cause an allocation
  865.        failure.
  866.        Unfortunately, there is a race condition since another thread
  867.        could run and do an allocation between the time the faulting NEW
  868.        returns and all references to the search tree are NIL'ed. This can
  869.        be mimimized by adding some slop to the safety net.
  870.      * An editor that allocates O(n) bytes of memory when opening an
  871.        n-byte file. If the users tries to open a huge file, you don't
  872.        want to crash, but rather tell the user that the file can't be
  873.        opened (in UNIX, the user can then kill some processes to regain
  874.        swap space and try again, or in an emacs-style editor he can
  875.        delete some buffers and try again). A callback won't work for
  876.        this, because when attempting to open a huge file, the allocation
  877.        must be aborted: there just isn't enough memory to go around.
  878.        Instead an RTAllocator.New() routine should be used for this
  879.        allocation.
  880.        However, the editor will also want to register a callback proc to
  881.        guard against NEW()s in other parts of the program that can't be
  882.        satisfied. If the callback is passed the size of the memory
  883.        allocation that can't be satisfied, the callback will be able to
  884.        pick between two strategies. If there is a 'safety net' which is
  885.        larger than the block to be allocated, the callback can free it
  886.        and set a "low on memory" flag, with the editor cleaning up
  887.        properly later. If the safety net is not big enough, the callback
  888.        itself can attempt an emergency save before crashing.
  889.        
  890.    Here's a specific proposal that embodies these ideas. We're not wedded
  891.    to the details. Note that RTCollector.LimitRelative is not essential:
  892.    it just lifts some of the functionality currently in RTHeapPolicy.
  893.    
  894.      * Add the following to RTCollector.i3:
  895.       PROCEDURE LimitAbsolute(n: CARDINAL);
  896.  
  897.       (* Don't let the heap grow beyond n bytes.  The collector/allocator
  898.          should observe this in all heap growth decisions.  *)
  899.  
  900.       [Comment from Hans: I don't think there is a way to write
  901.       programs that are reasonable citizens on a shared system without
  902.       some such facility.]
  903.  
  904.       PROCEDURE LimitRelative(x: REAL);
  905.  
  906.       (* Advisory.  Try to keep the heap size at roughly x times the
  907.          amount of live data. (For ref counting it affects only the
  908.          backup collector for cycles.)  *)
  909.  
  910.       [Comments from Hans: The performance of all collectors with
  911.       which I am familiar depends crucially on such a parameter.  Thus
  912.       it might as well be exposed in some portable interface.  (The
  913.       allocator should of course use less memory if it gains no time
  914.       advantage from using more.)  The "amount of live data" is, of
  915.       course, implementation defined, as are the minimum values of x
  916.       that have any chance of being observed.]
  917.      * In RTAllocator.i3, add OutOfMemory to RAISES clauses of all the
  918.        New routines, and add the following:
  919.       EXCEPTION OutOfMemory;
  920.  
  921.       TYPE
  922.          CallBackObj = OBJECT notify(bytes: CARDINAL) END;
  923.  
  924.       PROCEDURE RegisterHeapFullCallback(obj: CallBackObj);
  925.  
  926.       (* Add obj.notify to the list of procs to be called if an
  927.          allocation request is about to fail, either because of lack
  928.          of memory, or due to violation of an
  929.          RTCollector.LimitAbsolute imposed limit.  The notify method
  930.          will be called with an argument specifying the size in bytes
  931.          of the allocate call that triggered the callback.  The notify
  932.          method may not allocate or acquire locks, or call any
  933.          procedures that do.  It may be invoked synchronously with any
  934.          combination of locks held.  (Should there be a way to delete
  935.          a registered callback?).  If a garbage collection after this
  936.          callback fails to reclaim enough memory to allocate the
  937.          requested object, an exception will be raised if the
  938.          allocation was through RTAllocator.  Otherwise a checked
  939.          runtime error will result.  The notify proc is not called
  940.          when memory fails from an RTAllocator.New call (these
  941.          failures can be caught by the user).
  942.  
  943.          Typical actions by notify would include one of the following:
  944.  
  945.          1) Clearing pointers to reduce the amount of accessible memory.
  946.          2) Calling RTCollector.LimitAbsolute with a larger limit.
  947.       *)
  948.      * Variations on this proposal:
  949.        Might want to consider adding:
  950.       PROCEDURE GetLimitAbsolute(): CARDINAL;
  951.       (* Return the current absolute heap limit *)
  952.        The usefulness of RTCollector.LimitAbsolute in the callback would
  953.        be increased if there was a way to tell if this actually freed up
  954.        any more memory. One approach would be to change CallBackObj to
  955.       TYPE
  956.          CallBackObj = OBJECT
  957.                           notify(bytes: CARDINAL; retry: BOOLEAN): BOOLEAN
  958.                        END;
  959.        and change the action of RegisterHeapFullCallback to:
  960.       (* If a garbage collection after all callbacks have been
  961.          executed fails to reclaim enough memory to allocate the
  962.          requested object, then any notify() procs that returned TRUE
  963.          will be called again with retry := TRUE.  Otherwise an
  964.          exception will be raised if the allocation was through
  965.          RTAllocator, or else a checked runtime error will result. *)
  966.        Thus, if you wanted to first try and get more memory in the
  967.        callback by calling RTCollector.LimitAbsolute, you could return
  968.        TRUE and wait for a callback with retry = TRUE. If this second
  969.        callback occurs, you will need to clear some pointers to free up
  970.        memory. Or another variation: add
  971.       PROCEDURE GetTotalBytesAllocated(): CARDINAL;
  972.       (* Returns the total number of bytes allocated since the program
  973.          begin.  A CARDINAL may not be big enough, perhaps this should
  974.          be a LONGREAL? *)
  975.        Then the retry argument to the notify method can be eliminated,
  976.        since a call is a retry only if GetTotalBytesAllocated() shows no
  977.        additional allocations since the last callback.
  978.        
  979.    John DeTreville: When I read your March proposal for handling running
  980.    out of memory on the traced heap, I didn't quite see how to implement
  981.    the details you gave. I've been iterating to create mechanisms that
  982.    are simpler and more implementable, and I've now arrived at quite a
  983.    simple interface.
  984.    
  985.    In particular, I now believe that (almost) all the functionality you
  986.    ask for is already provided by the current interface. I say "almost"
  987.    because there's a few status calls to be added, and because some of
  988.    the current mechanisms are clunky, but I believe I can tell a
  989.    convincing story. Note that these mechanisms are or would be in
  990.    SRC-specific interfaces (currently called RTAllocatorSRC,
  991.    RTCollectorSRC, and RTHeapRep); I don't think we understand them well
  992.    enough to put them into the public IP interfaces.
  993.    
  994.    Let's first distinguish VM limits from application-imposed limits. The
  995.    amount of VM available to the application is a hard limit, although
  996.    not one that can easily be predicted. In the current SRC M3
  997.    implementation, both the allocator and the collector allocate VM from
  998.    the kernel when necessary. If the collector tries to allocate VM and
  999.    fails, the program must crash: there is no way to reestablish the
  1000.    necessary invariants to let it continue.
  1001.    
  1002.    I propose treating VM exhaustion as a checked runtime error, in the
  1003.    allocator and in the collector. The goal is then to establish and
  1004.    maintain an application-imposed limit that is uniformly stricter than
  1005.    the VM limit, whatever that may be.
  1006.    
  1007.    You propose a mechanism to allow calls to the New* procedures to fail
  1008.    if they would exceed the application-imposed limit. Of course, only a
  1009.    small part of the code would take advantage of this facility. This
  1010.    code could equally well query the heap to determine the current size,
  1011.    and compare it against the limit; if the program can also predict the
  1012.    size of the object to be allocated, it can decide whether or not to
  1013.    proceed.
  1014.    
  1015.    This approach requires some collector-dependent code in the
  1016.    application, but I doubt that it would be very much. It also allows
  1017.    possible race conditions, but I believe they're not much worse in
  1018.    practice than in the original proposal.
  1019.    
  1020.    You also propose a mechanism to notify the program whenever the limit
  1021.    is about to be exceeded. It's quite complicated to get such immediate
  1022.    notification. First, the procedures notified can't acquire locks or
  1023.    call most procedures in other modules. Second, it requires a new
  1024.    collection to run synchronously after the procedures to see if enough
  1025.    space has been freed and whether some of the procedures must be called
  1026.    again; this causes an interruption of service.
  1027.    
  1028.    Here's a different proposal, which might not allow space bounds as
  1029.    tight as in the original proposal, but which seems simpler. We would
  1030.    add a mechanism for an application thread to wait for the next
  1031.    collection to finish. This mechanism could replace the current
  1032.    mechanisms for registering and unregistering synchronous monitors,
  1033.    which have numerous complex and poorly documented constraints on what
  1034.    actions they can perform.
  1035.    
  1036.    Each time through, the thread could compare the amount of space still
  1037.    reachable to the application-imposed limit, and either free some data
  1038.    before the next collection (the ability to hold locks would be handy
  1039.    here) or increase "gcRatio" to make the collector work harder and keep
  1040.    the total heap size under control, or both.
  1041.    
  1042.    There is still the danger that the application could allocate so
  1043.    rapidly that this asynchronous thread might not be able to keep up,
  1044.    but otherwise asynchronous actions seem a lot more reasonable than
  1045.    synchronous.
  1046.    
  1047.    This is one approach, and there are others. What's nice about this
  1048.    design is that it requires almost no changes to the interface, only
  1049.    better status reporting and a replacement of the mechanisms for
  1050.    registering and unregistering synchronous collection monitors. Maybe
  1051.    you could even work around the current lack of these facilities. Let
  1052.    me know what you think.
  1053.    
  1054.    Hans: One quick comment, without having thought much about the rest:
  1055.    
  1056.    "This code could equally well query the heap to determine the current
  1057.    size, and compare it against the limit; if the program can also
  1058.    predict the size of the object to be allocated, it can decide whether
  1059.    or not to proceed."
  1060.    
  1061.    Is this really true? Since the collector can't move some objects,
  1062.    there are presumably fragmentation issues. Am I guaranteed to be able
  1063.    to allocate 1 MB if the current heap size is 1 MB below the limit?
  1064.    This is certainly false in PCR, and I'm not sure how you could
  1065.    guarantee it without remapping pages.
  1066.    
  1067.    John: Hans Boehm notes that I was wrong about the client of New* being
  1068.    able to predict whether an allocation would succeed or fail, because
  1069.    of likely page-level fragmentation. This needs to be fixed in my
  1070.    proposal.
  1071.    
  1072.    To expand on my earlier message, let me outline a completely different
  1073.    approach for handling heap overflow, that perhaps has more in common
  1074.    with the original PARC proposal, but which seems far too complex and
  1075.    unwieldy to me. This complexity is why I tried to work out a simpler
  1076.    approach, even at the cost of providing fewer guarantees.
  1077.    
  1078.    We start by imagining that we want to be able to continue to run even
  1079.    if we exhaust VM. First, this means that we can never allocate VM from
  1080.    inside the collector. The implication is that whenever we allocate VM
  1081.    in the allocator, we allocate enough extra to tide us over through the
  1082.    next collection, no matter how much of the heap it retains. This
  1083.    suggests that we will significantly overallocate VM. For example, with
  1084.    a stop-and-copy collector and gcRatio set to 1, a program with a
  1085.    stably-sized reachable set currently requires 3 times as much space as
  1086.    the reachable set, but the "failsafe gc" would require 4 times.
  1087.    
  1088.    (Doing even this well depends crucially upon the SRC implementation
  1089.    detail that the current collector never copies objects bigger than one
  1090.    page, but leaves them in place. Otherwise, the possibility of
  1091.    fragmentation would make it much more difficult to determine how much
  1092.    memory to leave free for the collector, and in what sizes of runs of
  1093.    pages. It will also take some work to avoid off-by-one errors in
  1094.    predicting how much memory a collection could take.)
  1095.    
  1096.    Of course, if the client decreases gcRatio, or switches from
  1097.    sort-and-copy collection to concurrent collection, that would require
  1098.    allocating more VM, to ensure that the collector cannot run out of VM.
  1099.    That means that these operations can also fail, just like allocator
  1100.    operations.
  1101.    
  1102.    Only some programs will want to be able to back off when they reach VM
  1103.    limits. Others won't mind getting a checked runtime error; in return,
  1104.    they will require less VM. Therefore, we need procedures to switch
  1105.    back and forth between these two modes. Again, attempting to switch to
  1106.    failsafe mode can fail.
  1107.    
  1108.    The collector currently allocates its own space on the traced heap
  1109.    during collections, which will have to be moved to the untraced heap
  1110.    if we are to predict how much traced heap a collection can use. Note
  1111.    that in general, once VM is exhausted, allocations on the untraced
  1112.    heap may start to fail, and so programs will probably die very quickly
  1113.    once VM is exhausted. But let's move on.
  1114.    
  1115.    In addition to the VM limit, we also want an application-imposed limit
  1116.    on heap size. The allocator and collector will guarantee that the heap
  1117.    size will never exceed this limit. Again, we will overallocate VM in
  1118.    the allocator to avoid exceeding the limit in the collector. Again,
  1119.    setting the limit may fail.
  1120.    
  1121.    So what happens when a NEW fails, or a New*, or switching to
  1122.    concurrent collection, or setting the application-imposed limit, or
  1123.    whatever? This happens whenever performing the operation would exceed
  1124.    the application-imposed limit, or when attempts to allocate enough
  1125.    extra VM fail.
  1126.    
  1127.    Some of these can signal an error, and the client can chose to do
  1128.    something else instead. In some cases, such as setting gcRatio, it
  1129.    might make sense for the failing operation to tell the client how
  1130.    close to the impossible value would be possible.
  1131.    
  1132.    NEW, though, should not signal an error; this would require massive
  1133.    changes in all existing modules that would not be add value to most
  1134.    clients. In this case, I can't think of anything much better than the
  1135.    original proposal. Before attempting to allocate the object, the
  1136.    collector will try to free up some storage. First, it can perform a
  1137.    collection, or finish the current one. If that doesn't do it, it can
  1138.    call one or more procedures registered by the application to drop
  1139.    links to some storage, or to change collector parameters. If that
  1140.    doesn't do it, we can perform another collection. And so on and so on,
  1141.    until the procedures say to give up.
  1142.    
  1143.    Note that these collections must be synchronous, since no allocations
  1144.    may be possible until this mechanism completes, and the collections
  1145.    will therefore cause interruptions of service. Note also that the
  1146.    procedures cannot acquire locks, cannot allocate storage, cannot call
  1147.    thread primitives, and so on, and therefore cannot call into most
  1148.    libraries; they are essentially restricted to reading and writing data
  1149.    structures whose implementations they know, and changing collector
  1150.    parameters. This seems excessively restrictive, but also unavoidable
  1151.    in this approach.
  1152.    
  1153.    In short, this seems like a lot of extra mechanism to add to the
  1154.    allocator and collector, that doesn't seem to do quite what you want;
  1155.    it gives you strict limits, but at a cost. My proposal of this morning
  1156.    is at least much simpler, although it can give looser limits.
  1157.    
  1158.    John, continuing: Thinking a little more about the problem of running
  1159.    out of storage in the untraced heap, it seems that the only reasonable
  1160.    thing to do is to merge the implementation of the untraced heap with
  1161.    the traced heap. This was, untraced NEWs that fail can be handled
  1162.    exactly the same way as traced NEWs, with a synchronous cleanup
  1163.    routine that frees enough VM to proceed, or resets parameters.
  1164.    
  1165.    This means that the allocator and collector cannot use the untraced
  1166.    heap, but must either use a static amount of storage which they could
  1167.    overflow, or must allocate enough extra in response to client
  1168.    applications that they cannot possibly run out of space. The potential
  1169.    space overhead for maximum-sized stacks, for example, is huge.
  1170.    
  1171.    The more this proposal is fleshed out, it more it seems that doing a
  1172.    good job of recovering from heap overflows is quite tricky, which is
  1173.    why I suggest a lower-tech approach for now.
  1174.    
  1175.    Hans: I just went over the last few messages in this thread again. I
  1176.    think the bottom line is, as you say:
  1177.    
  1178.    It's hard to implement an out-of-memory call-back on top of the
  1179.    current collector. Given the current collector, a collector call-back
  1180.    that allows polling is probably the best you can reasonably do, and
  1181.    should certainly be provided.
  1182.    
  1183.    The remaining question, which also seems to be motivated by other
  1184.    concerns here, is: To what extent are you tied to this collector
  1185.    design? The problem here seems to be mainly caused by copying old
  1186.    generation objects, since you could perhaps bound the size of the
  1187.    young generation? My suspicion, based unfortunately only on anecdotes,
  1188.    is that this is not a good idea anyway, since it uses too much space,
  1189.    and is also fairly expensive in copying cost. (PARCPlace seems to have
  1190.    arrived at the same conclusion, so there's probably at least one other
  1191.    supporter of this position. Some recent complaints here about space
  1192.    usage of Modula-3 programs also point a bit in this direction.)
  1193.    
  1194.    Do you agree? If so, should the interface be designed ignoring current
  1195.    constraints, and should we initially accept a partial implementation?
  1196.    
  1197.    John: It's been a while, so let me recap where we are, or at least
  1198.    where I am.
  1199.    
  1200.    We've been discussing mechanisms for Modula-3 programs to manage their
  1201.    memory better. In particular, we have proposed ways that programs
  1202.    could bound the heap size and recover from heap overflow.
  1203.    
  1204.    I think this topic is complicated enough, and new enough, that we
  1205.    shouldn't try to get it into the current set of portable interfaces.
  1206.    The Interface Police concur.
  1207.    
  1208.    We've floated two broad (families of) proposals for attacking this
  1209.    problem:
  1210.    
  1211.      * Allow strong guarantees on the heap size; these guarantees would
  1212.        never be broken.
  1213.      * Allow the program to monitor its memory usage, discarding excess
  1214.        data as necessary.
  1215.        
  1216.    I think that the first is achievable. Adapting the current SRC
  1217.    Modula-3 (allocator and) collector to allow such guarantees would take
  1218.    a month or so. The principal problem is that the current collector
  1219.    tries to maximize space/time performance, and giving such guarantees
  1220.    will probably require extra memory to be set aside that will never be
  1221.    used. The collector would have two modes: with or without guarantees.
  1222.    Most programs would run without guarantees.
  1223.    
  1224.    I also think that a usable version of the second is possible with
  1225.    almost no change to the current collector. The programmer would have
  1226.    to do more work, and wouldn't get any strong guarantees, but this
  1227.    approach should work for many programs.
  1228.    
  1229.    We've also been discussing a third family of proposals, that seem to
  1230.    combine the worst features of the first and second: they require
  1231.    significant changes to the current collector, but son't give very
  1232.    strong guarantees. These seem much less interesting to me.
  1233.    
  1234.    Here's two pieces of opinion.
  1235.    
  1236.    First, I propose that we work out the details of #2, and you use it
  1237.    for a couple of programs. Get some experience with it. This could help
  1238.    inform a heavier-weight solution.
  1239.    
  1240.    Second, I wonder whether any of these solutions is a good candidate
  1241.    for a portable interface. It's one thing not to be strictly
  1242.    incompatible with a given collector strategy, but quite another to be
  1243.    easy to plug into an existing collector. Modula-3 currently doesn't
  1244.    require very much from its collector; making these proposals standard
  1245.    would significantly increase the requirements on a Modula-3
  1246.    implementor.
  1247.    
  1248. Why uppercase keywords?
  1249.  
  1250.    Some people prefer uppercase keywords others hate them. Another
  1251.    possibility is to accept both forms for keywords. This topic has been
  1252.    discussed at length and there is no solution that will completely
  1253.    satisfy everyone's tastes. Fortunately this is a very minor issue and
  1254.    you can easily have lowercase keywords automatically converted for you
  1255.    using an emacs macro package like [26]m3su .
  1256.    
  1257. Why CONST Comments in Variables Declarations?
  1258.  
  1259.    John Kominek (kominek@links.uwaterloo.ca) wrote: Sprinkled throughout
  1260.    SRC m3 you'll find "constant" variables exported in interfaces. For
  1261.    instance,
  1262.  
  1263.    VAR (*CONST*) Grain: LONGREAL;
  1264.  
  1265.    where Grain is assigned during module initialization. Instead, did the
  1266.    modula-3 designers consider doing this.
  1267.    READONLY Grain: LONGREAL;
  1268.  
  1269.    Here the keyword permits only exporting modules to modify the Grain
  1270.    variable. Is there a problem with this proposal? The READONLY keyword
  1271.    is successfully used at procedure boundaries, so why not also at
  1272.    interface boundaries?
  1273.    
  1274.    Bill Kalsow replies:
  1275.    
  1276.    A problem with this proposal is that any module can claim to export
  1277.    the interface containing the variable, hence any module could modify
  1278.    the variable. Note that CONST says more than just READONLY. CONST
  1279.    implies that the variable should not be modified by clients and that
  1280.    once it is initialized, it won't be changed later by the
  1281.    implementation. READONLY would only mean that clients should not
  1282.    modify the variable. IMO, the "right" solution would have been to
  1283.    allow:
  1284.     INTERFACE Foo;
  1285.     CONST x: T;
  1286.  
  1287.     MODULE Foo;
  1288.     CONST x: T := <value>;
  1289.  
  1290.    In the same way it checks revelations for opaque types, the compiler
  1291.    could check that only one module provided a value for the constant.
  1292.    But, this proposal doesn't quite hang together either. Consider this
  1293.    example:
  1294.     CONST x: INTEGER;
  1295.     VAR   v: [0..x];
  1296.  
  1297.    The language definition says that "v"s definition is illegal if "x <
  1298.    0" because its type is "empty". The system could refuse to run the
  1299.    program by delaying the check until it had seem the corresponding
  1300.    implementation module. But, I think you'll agree that it could quickly
  1301.    turn into a mess. The most flexible handling of opacity I've seen is
  1302.    in Christian Collberg's PhD Thesis, "Flexible Encapsulation". It was
  1303.    published Dec 5, 1992 by the CS Dept at Lund University, Lund Sweden.
  1304.    If I remember correctly, his system was capable of deferring all
  1305.    checks and decisions imposed by opaque declarations until link time.
  1306.  
  1307. References
  1308.  
  1309.    1. mailto:michel.dagenais@polymt.ca
  1310.    2. http://m3.polymtl.ca/m3
  1311.    3. http://www.cmass.com/cm3/projects.html
  1312.    4. http://www.cmass.com/
  1313.    5. http://www.elego-software-solutions.com/
  1314.    6. http://www.m3.org/cm3/
  1315.    7. file://localhost/home/m3/tmp/m3/pm3/intro/src/concise-bib.html
  1316.    8. file://localhost/home/m3/tmp/m3/pm3/intro/src/bib.html
  1317.    9. file://localhost/home/m3/tmp/m3/pm3/intro/src/bib.html#SPwM3
  1318.   10. file://localhost/home/m3/tmp/m3/pm3/intro/src/bib.html#m3-Har92
  1319.   11. http://www.m3.org/
  1320.   12. http://www.research.digital.com/SRC/modula-3/html/home.html
  1321.   13. http://m3.polymtl.ca/m3
  1322.   14. ftp://ftp.cs.colorado.edu/pub/cs/techreports/zorn/CU-CS-641-93.ps.Z
  1323.   15. http://www.research.digital.com/SRC/modula-3/html/home.html
  1324.   16. http://www.cmass.com/
  1325.   17. http://www.m3.org/cm3/
  1326.   18. http://m3.polymtl.ca/m3
  1327.   19. http://m3.polymtl.ca/
  1328.   20. http://www.cs.washington.edu/research/projects/spin/www/
  1329.   21. file://localhost/home/m3/tmp/m3/pm3/language/modula3/m3tools/m3gdb/src
  1330.   22. file://localhost/home/m3/tmp/m3/pm3/text/sgmltools/sgml/src/nsgmls
  1331.   23. mailto:rrw1000@cus.cam.ac.uk
  1332.   24. file://gatekeeper.dec.com/pub/DEC/Modula-3/
  1333.   25. http://gatekeeper.dec.com/pub/misc/detlefs/escover.ps
  1334.   26. ftp://pion.lcs.mit.edu/pub/m3su
  1335. -- 
  1336.  
  1337. Prof. Michel Dagenais               http://m3.polymtl.ca/dagenais
  1338. DΘpartement de gΘnie informatique   michel.dagenais@polymtl.ca
  1339. Ecole Polytechnique de MontrΘal     tel: (514) 340-4711 ext.4029
  1340.