Date: Mon, 1 Jul 91 16:02:00 EDT From: wyant@saber.com Subject: Instantation of Generics This is undoubtably premature...but I'll ask anyway. What though has been given to the instantiation and management of generic interfaces ? Is there a model worked out yet ? What about managing "pools" of previously instantiated and compiled generic interfaces ? Always curious... Geoff Wyant wyant@saber.com ------------------------------------------------------------------------------ Date: Mon, 1 Jul 91 15:59:45 PDT From: Subject: Modula 3 and C While all new code in Hector will be in Modula 3, we're planning to leave Sarpedon (the editor for dictionary entries) in C, as much as possible. Two questions: (1) Are there examples lying about somewhere, showing how to combine M3 and C? I'm thinking about naming conventions, initialization procedures, who's in charge of memory allocation, etc. (2) We've been using a simple exception-handling mechanism (Eric Roberts' TRY/EXCEPT and TRY/FINALLY macros), which is based on setjmp. Obviously, we'd like to use the "real" exception mechanism that comes with M3. Is it conceivable to rewrite Eric's macros to generate the same code that the M3 compiler would? [Optimal, since the source (calling) code wouldn't change.] If not, is it conceivable to write code "by hand" that's the same as (or close enough to) the code that the M3 compiler generates? Any help on this would be greatly appreciated. ------------------------------------------------------------------------------ Date: 2 Jul 91 11:30:12 GMT From: piet@cs.ruu.nl (Piet van Oostrum) Subject: Problems with installing 1.6 on HP-UX I have some problems with installing the 1.6 distribution on HP-UX. I didn't have these problems with the beta version if I remember correctly. I couldn't install the new version earlier because of a disk crash. Firstly, the gethostid() call is nonexistant on HP-UX. I just deleted that. Secondly on building m3compiler the command line .ROOT/system/driver/m3.local -D../Interfaces -w1 -X1@+Ns4000@ -X1@+O1@ -o m3com piler \ builtinOps/Abs.io builtinOps/Abs.mo builtinOps/Adr.io builtinOps/Adr.mo built....................... gets way too long. There is a limit on the command line length in make (2500 bytes) but even when I use gnumake it complains: make[1]: execve: .ROOT/system/driver/m3.local: Arg list too long HP-UX seems to have a limit of 5120 on execv arg list length. I guess a solution would be to put all the modules in a library (building them directory by directory) or doing a ld -r per directory. However I would like to know if there is a simpler solution. -- Piet* van Oostrum, Dept of Computer Science, Utrecht University, Padualaan 14, P.O. Box 80.089, 3508 TB Utrecht, The Netherlands. Telephone: +31 30 531806 Uucp: uunet!mcsun!ruuinf!piet Telefax: +31 30 513791 Internet: piet@cs.ruu.nl (*`Pete') ------------------------------------------------------------------------------ Date: 2 Jul 91 13:16:53 GMT From: moss@cs.umass.edu (Eliot Moss) Subject: Re: Instantation of Generics I'm sorry but I don't fully understand your question. The "Twelve Changes" document describes a generics system and gives the meaning of generic interfaces and generic modules. The basic idea is that interfaces and modules may be parameterized with a number of formal variables. These formal variables are then bound to actual interface names and a substitution performed to expand the paramterized interface/module into an instantiated one. Since interface names are unique within a program, it would seem relatively easy to insure that each instantiation is performed exactly once. If this answers your question, then great; otherwise, perhaps you could clarify it for me? -- J. Eliot B. Moss, Assistant Professor Department of Computer and Information Science Lederle Graduate Research Center University of Massachusetts Amherst, MA 01003 (413) 545-4206, 545-1249 (fax); Moss@cs.umass.edu ------------------------------------------------------------------------------ Date: 2 Jul 91 13:21:41 GMT From: moss@cs.umass.edu (Eliot Moss) Subject: Re: Modula 3 and C I suspect the answer depends on whether you're talking about SRC Modula-3 or GNU Modula-3 (my research group is producing the latter, and hope to have something out in a year or less). Undoubtedly there will be SOME way to interact with C routines for each system, but it will not be the same, especially in the area of exceptions. For GNU Modula-3 we are generating tables and avoiding any normal case code (no setjmp/longjmp hackery in particular). I don't know any C compiler that can do this at present, though since we're basing our work on gcc, and it might be merged back with standard gcc, you might get gcc 2.0 style exceptions with our table driven implementation as an option (selected on the gcc command line or something). I believe that the SRC M3 folks are considering redoing the exception handling, so you'd better track that if exception handling is a must for you .... -- J. Eliot B. Moss, Assistant Professor Department of Computer and Information Science Lederle Graduate Research Center University of Massachusetts Amherst, MA 01003 (413) 545-4206, 545-1249 (fax); Moss@cs.umass.edu ------------------------------------------------------------------------------ Date: 2 Jul 91 17:18:28 GMT From: tima@agora.rain.com (Tim Anderson) Subject: I might try to port Modula-3, coupla hints please! I was thinking of trying out Modula-3 on our 4D/20. The list of supported O.S's is: Ultrix 3.1 SunOS 4.0.3 Domain/OS 10.2 HP-UX 7.0 AIX 3.1 IBM/4.3 (AOS 4.3) UMAX 4.3 RISC iX 1.21 Out of that list, which would be the best one to start with? Apparently there are some BSD features in SRC Modula-3 that make it difficult to run on a SYSV box, such as long file names, and symbolic links. Not being particularly familiar with IRIX or UNIX in general I can't make too many statements regarding the difficulty of this task... For those not familiar with the SRC M3 distribution, it is a M3 -> C translator, and they supply the translated C source for the initial bootstrap. Maybe I should play with GNU gcc++ instead... tima@agora.rain.com ------------------------------------------------------------------------------ Date: 2 Jul 91 23:01:57 GMT From: rrogers@sumax.seattleu.edu (Richard Rogers) Subject: Help With GENERICs Hello, I don't have access to a Modula-3 compiler, but I've been reading through the report and the 12 Changes document. The part that explains generics is a bit confusing, so I am hoping that someone out there who understands them can tell me if I've got things straight. Say I wanted to write a generic sorting procedure that could sort any array of objects with a method "less" for telling whether two objects are in the right order. Would this work: GENERIC INTERFACE Sort (BaseMod); TYPE BaseType = BaseMod.BaseType; PROCEDURE SortAny (VAR a : ARRAY OF BaseType); END Sort. GENERIC MODULE Sort (BaseMod); PROCEDURE SortAny (VAR a : ARRAY OF BaseType) = VAR temp : BaseType; BEGIN FOR i := FIRST (a)+1 TO LAST (a) DO FOR j := LAST (a) TO i BY -1 DO IF a[j-1].less(a[j]) THEN temp := a[j-1]; a[j-1] := a[j]; a[j] := temp END END END END SortAny; END Sort. INTERFACE Integer; TYPE BaseType = OBJECT i : INTEGER; METHODS less (x : BaseType) : BOOLEAN; END; END Integer. INTERFACE Real; TYPE BaseType = OBJECT r : REAL; METHODS less (x : BaseType) : BOOLEAN; END; END Real. INTERFACE SortInt = Sort (Integer) END SortInt. INTERFACE SortReal= Sort (Real) END SortReal. Then, to use these in some program, I would have to: IMPORT SortInt, SortReal; ... SortInt.SortAny (ArrayOfIntegers); SortReal.SortAny (ArrayOfReals); ... Now compiling the program would cause GENERIC MODULE Sort to be compiled twice, creating an integer version and a real version? And these versions do not share any code (ie: two separate object files or something)? Is there a better way to do this? Thanks, Richard Rogers rrogers@seattleu.edu ------------------------------------------------------------------------------ Date: Tue, 2 Jul 91 23:13:39 PDT From: muller@src.dec.com (Eric Muller) Subject: Re: Help With GENERICs If you are using generics, then you probably don't need objects, as the arguments to the generic can provide the appropriate less function: GENERIC INTERFACE Sort (Ord); PROCEDURE Sort (VAR a: ARRAY OF Ord.T); END Sort. GENERIC MODULE Sort (Ord); PROCEDURE Sort (VAR a: ARRAY OF Ord.T) = ... IF Ord.Less (a [j-1], a [j]) THEN ... END Sort. INTERFACE SortMyRecord = Sort (MyRecord); END SortInt. MODULE SortMyRecord = Sort (MyRecord); END SortInt. INTERFACE MyRecord; TYPE T = RECORD a: INTEGER; END; PROCEDURE Less (x, y: T): BOOLEAN; MODULE MyRecord; PROCEDURE Less (x, y: T): BOOLEAN = BEGIN RETURN x.a < y.a; END Less; END MyRecord. Note that the generic can take anything from its formal interfaces: types, functions, ... > Now compiling the program would cause GENERIC MODULE Sort to be compiled > twice, creating an integer version and a real version? Yes. > And these versions do not share any code (ie: two separate object > files or something)? In general, I think is very difficult to reuse the object code for two different instances. Even with the simple case we have, the arguments to the Less function can be simple integers or arbitrary records; the size of the temp variable (for the exchange) depends on the particular instance. (By the way, it would probably be better to declare the arguments of Less to be READONLY.) If you share, you will loose big on optimizations. But you can also have an purely object version: TYPE T = OBJECT METHOD Less (x: T): BOOLEAN; END; PROCEDURE Sort (VAR a: ARRAY OF T) = ... IF a[j-1].Less (a[j]) THEN ... TYPE Int = T OBJECT i: INTEGER; METHODS OVERRIDES Less := IntLess; END; TYPE Real = T OBJECT r: Real METHODS OVERRIDES Less := RealLess; END; PROCEDURE IntLess (self: Int; x: T) = BEGIN RETURN (self.i < NARROW (x, Int).i); END IntLess; PROCEDURE RealLess (self: Real; x: T) = BEGIN RETURN (self.r < NARROW (x, Real).r); END IntLess; In the object version, you can actually build an ARRAY OF T that contains both Int and Real; if this is the case and you happen to compare two such things, the NARROW will fail. -- Eric. ------------------------------------------------------------------------------ Date: 3 Jul 91 12:58:30 GMT From: moss@cs.umass.edu (Eliot Moss) Subject: Re: I might try to port Modula-3, coupla hints please! A minor correction: saying that SRC Modula-3 is an M3 to C translator may be misleading. SRC M3 is a true compiler whose target happens to be C rather than assembly or machine code. Unfortunately, I am not in a position to address your real question (which port to start with for getting M3 up on a 4D/20). I urge you to work with M3 though -- there are too many C++ bigots already! :-) Note also that GNU Modula-3 is in the works (my research group at UMass is developing it), though it will be a while before it is ready (more money would get it ready faster ...) Eliot -- J. Eliot B. Moss, Assistant Professor Department of Computer and Information Science Lederle Graduate Research Center University of Massachusetts Amherst, MA 01003 (413) 545-4206, 545-1249 (fax); Moss@cs.umass.edu ------------------------------------------------------------------------------ Date: 3 Jul 91 13:06:23 GMT From: harbison@bert.pinecreek.com (Sam Harbison) Subject: Modula-3 newsletter The first issue of the Modula-3 newsletter was mailed last week to everyone on my mailing list. US recipients should have received it by now. Foreign recipients who do not receive the newsletter after a time appropriate for first class/air mail letters should contact me. Eventually, the textual contents of the newsletter (i.e., minus photographs and graphics) will be archived at gatekeeper.dec.com. Of course, you really want the pretty version, so you can leave it where lots of other other people will see it. Sam Harbison Pine Creek Software; 305 S. Craig St., Suite 300; Pittsburgh, PA 15213 +1 412 681 9811; harbison@bert.pinecreek.com ------------------------------------------------------------------------------ Date: Wed, 3 Jul 91 11:14:28 PDT From: muller@src.dec.com (Eric Muller) Subject: Re: Modula-3 newsletter In article <1991Jul3.130623.27597@bert.pinecreek.com>, Sam Harbison writes: > Eventually, the textual contents of the newsletter (i.e., minus > photographs and graphics) will be archived at gatekeeper.dec.com. It is now available from gatekeeper.dec.com, in pub/DEC/Modula-3/newsletter/issue-1-jun91.txt.Z -- Eric. ------------------------------------------------------------------------------ Date: Wed, 3 Jul 1991 16:25:13 -0500 (CDT) From: Dick Orgass Subject: Re: New organization of SRC Modula-3 With some limitations, I'd like to record my support for Eric's proposed new organization of SRC Modula-3. I view the first goal as important and, with some restrictions, support his proposed implementation. There are, however, some places where I'd go for a different implementation. For example, m3tk is distributed with makefiles generated by the tool m3check. These generated make files are accurate and provide good examples of how to use the tool. I think m3tk should be distributed using the tool generated make files instead of imake. There may well be other cases where this same statement could be made. I like Eric's proposal for dealing with target specific versions of files; it will make the whole build much simpler. Question: Is it intended that version 2.0 will write ANSI C or will the output continue to be somewhere between BSD C and ANSI C? I hope that the file names will continue to be as long as needed to preserve the existing relationship between interface/module name and the file name (plus extension). I think artificial shortening of interface/module names would be a mistake and make it harder to read Modula-3 code. In the case of the IBM platforms, symbolic links and file name lengths are not an issue. Dick ------------------------------------------------------------------------------ Date: 3 Jul 91 16:25:14 GMT From: Peter.Dickman@cl.cam.ac.uk Subject: CFP - OOPSLA 91 Workshop on Objects in Large Distributed Applications [Apologies if this is a duplicate posting, there were problems getting it out] Call for Participation OOPSLA '91 Workshop on Objects in Large Distributed Applications Monday 7th October Object-based programming is the most promising software technology with which to develop large applications. However, there remain a variety of problems to be addressed where distributed object-based systems are concerned. For example, the issues of scale, organizational autonomy (and security) and the efficient support of tools for inter-organization co-operative working must be coherently resolved if best advantage is to be obtained from current hardware developments. An environment in which a worldwide Broadband ISDN internet links a multitude of organizations offers substantial challenges to the software development community. Particularly when each site has an internal network of multi-media workstations and high-performance specialised servers. The workshop will be structured to provide a forum on the use of objects in solving the problems posed by such near-future systems. A number of topics have been identified, from language-level issues concerning the programming models appropriate for widely-distributed applications, to the object-support mechanisms needed for efficiently providing a coherent object model that spans a WAN. ---------------------------------------- The workshop is aimed primarily at those researching into or working with: - scalable object architectures - large scale applications - object-support operating systems - distributed object-based languages the core theme being the support required for large distributed applications. Although it is not intended that language concepts be highlighted in this workshop, it is clear that some language implementation issues will arise. ---------------------------------------- Possible topics for submissions include, but are not limited to: Basic Issues: Naming, location & invocation for widely-distributed object-based applications. Scalable garbage collection and load balancing. Models: Object management architectures spanning autonomous organisations (proposals and implementations). Applications: Widely-distributed applications, particularly applications involving a high degree of interaction (such as multi-media collaboration tools) across large networks. The workshop will be divided into sessions, most of which will consist of invited presentations followed by moderated discussions. Depending on the received submissions there may be one or two panel-based sessions. ---------------------------------------- Extended abstracts or position papers of not more than five pages describing recent work and addressing the above topics are sought. Unfortunately only one person can be accommodated for each accepted position paper (except under special circumstances). The papers will be reviewed and acceptance will be based on relevence to the theme of the session and quality/clarity of the paper. A range of different views and approaches will be selected and experience reports covering the construction of large-scale applications and/or scalable object-support systems will be especially welcome. Attendance will be by invitation only, based on the accepted papers, and all attendees (hopefully abut 30) must register for OOPSLA '91. Extended abstracts must be submitted before August 1, 1991: ----------------------------------------------------------- Preferred form: Plain text or \LaTeX sent by e-mail: (With subject line "OOPSLA-OLDA" please) Peter.Dickman@cl.cam.ac.uk Alternative form: A single high quality copy sent by post: Peter Dickman (OOPSLA - OLDA) Computer Laboratory New Museums' Site Pembroke Street Cambridge CB2 3QG United Kingdom Brief e-mail messages declaring that you intend to submit a position paper would be appreciated, to ease administration. Such a message is particularly important if you are submitting your abstract by post from outside the UK. Please include both normal and electronic mail addresses with your paper. Most accepted abstracts will be circulated electronically beforehand, however those who submit paper copies will be asked to bring copies of their abstracts for distribution at the start of the workshop. Important Dates: ----------------- August 1 Deadline for receiving extended abstracts. September 1 Notification of invitation or rejection. October 7 Workshop Date ------------------------------------------------------------------------------ Date: 4 Jul 91 09:35:50 GMT From: ZVM056@DMSWWU1C.BITNET Subject: What is Modula-3 ?? I occasionally discovered this group, but I never heard of modula-3 before. Can somebody explain the differences to modula-2 ? According to the already existing articles I suppose that there is a generic typing feature. This would be very interesting to me because I miss this feature when using modula-2. Holger zvd006@dmswwu1c.bitnet Holger Klawitter Westfaelische Wilhelms-Universitaet, Germany (internet: holger@math.uni-muenster.de) ------------------------------------------------------------------------------ Date: 4 Jul 91 14:36:51 GMT From: moss@cs.umass.edu (Eliot Moss) Subject: Re: What is Modula-3 ?? Briefly, Modula-3 adds object types in a single inheritance hierarchy, true garbage collection, threads (parallel processes in the same address space) instead of coroutines, exception handling, and (more recently) generic interfaces and modules. The language report (which does not yet include a description fo the last feature) is available via anonymous ftp from gatekeeper.dec.com in directory pub/DEC/Modula-3/report as Report.ps.Z (but see the readme file). Release 1.6 SRC Modula-3 is also hanging off of pub/DEC/Modula-3; this generates C code and has been ported to a number of machines. There are files there describing the licensing procedure (simple and free). Some features of Modula-2 are dropped, notably variant records (subsumed by object types) and nesting of modules. To find out about generics, see the comp.lang.modula3 archives on gatekeeper and look for the "Twelve Changes to Modula-3" posting. Regards -- Eliot Moss -- J. Eliot B. Moss, Assistant Professor Department of Computer and Information Science Lederle Graduate Research Center University of Massachusetts Amherst, MA 01003 (413) 545-4206, 545-1249 (fax); Moss@cs.umass.edu ------------------------------------------------------------------------------ Date: 5 Jul 91 09:34:30 GMT From: guido@cwi.nl (Guido van Rossum) Subject: initialization questions OK, I got my M3 Newsletter in the mail, all the way in Amsterdam. Looks good! But... the "tips" section on initialization left me feeling unhappy. (1) The suggested way to ensure that users call the object's initialization method before doing anything else with the object involves adding a boolean field 'initCalled' to each object and to test its value in each method. This leaves me feeling unhappy about wasted memory bytes and wasted cycles. Isn't there a way to disallow calls to NEW() altogether, and providing a function instead that returns a new object? (I know this won't do for subclasses; but the interface for subclasses might reveal more than the interface for simple clients.) (2) It is argued that you don't need finalization procedures (destructors) because M3 has garbage collection. But what if your object contains a reference to something in the outside world that needs being released, e.g., an open file? (I understand that you can't guarantee to things the outside world that you will call their close functions; but in a UNIX situation, for instance, I may run out of open file descriptors if I can't close the ones that the application has forgotten about. The M3 library may well have solves this particular case; but how do I solve other instances of it?) --Guido van Rossum, CWI, Amsterdam Honary Member, Royal Society for Putting Things on Top of Other Things ------------------------------------------------------------------------------ Date: 5 Jul 91 12:51:49 GMT From: moss@cs.umass.edu (Eliot Moss) Subject: Re: initialization questions In article <3815@charon.cwi.nl> guido@cwi.nl (Guido van Rossum) writes: (1) The suggested way to ensure that users call the object's initialization method before doing anything else with the object involves adding a boolean field 'initCalled' to each object and to test its value in each method. This leaves me feeling unhappy about wasted memory bytes and wasted cycles. Isn't there a way to disallow calls to NEW() altogether, and providing a function instead that returns a new object? (I know this won't do for subclasses; but the interface for subclasses might reveal more than the interface for simple clients.) Sounds as if we should consider disallowing NEW on opaque types and partial revelations, though that would force use of a method provided in the scope of the definitive revelation, whether that was actually necessary or not. This seems like a good rule of thumb, anyway, and perhaps grounds for a compiler to issue a warning message about programming style. (2) It is argued that you don't need finalization procedures (destructors) because M3 has garbage collection. I would say that the need for finalization may be less than in (say) C++, since many C++ destructors are only there help free storage, which need is obviated by garbage collection in M3. But there certainly are important cases where finalization is necessary. It is still an area of investigation and each system is handling it differently, though there have been proposals discussed here in the past. We are working (though not all that hard yet) on a design that will integrate finalization with our approach to garbage collection in the gc scheme we will offer with GNU Modula-3. (I should add that I have been largely swayed to allow at least one other gc scheme to be used with GNU Modula-3, some kind of ambiguous roots collector, which requires less compiler support; it should be possible to incorporate finalization with that collector, too.) Regards -- Eliot -- J. Eliot B. Moss, Assistant Professor Department of Computer and Information Science Lederle Graduate Research Center University of Massachusetts Amherst, MA 01003 (413) 545-4206, 545-1249 (fax); Moss@cs.umass.edu ------------------------------------------------------------------------------ Date: 5 Jul 91 17:10:27 GMT From: gkt@iitmax.iit.edu (George Thiruvathukal) Subject: Tools for Effective Software Maintenance Hello Netlanders, Please accept my apologies in advance, as I realize the subject of my article is probably not appropriate for discussion in the language newsgroups; however, I could not find a newsgroup in my .newsrc file which appeared suitable for a discussion of the subject of my article. Because I read the languages groups avidly and am cognizant of the size and nature of the audience, I believe I can glean some decent input from some of my favorite languages newsgroups. The favor of a personal reply is requested to gkt@iitmax.iit.edu (for readers on Internet) or thirgeo@iitvax (for readers on BITNET). I would like to know (from professionals who are developing moderate to large scale software applications) what tools you are using to maintain your software . Also, I would appreciate a summary of the "good" and "bad" features of the tools. I am aware of the existence of SCCS and RCS and have read papers which discuss these tools. There are other tools for which I have obtained papers but as yet have not read them. Regardless of what tools you are using, I am interested in learning "how" they are being used to solve your software maintenance problems. In your responses, please include information about your company/institution, the type of software you develop, the size of your software development team, the size (either average or estimated) of your largest software project(s), the language(s) you use, the operating system(s) you use, and the tool(s) you use. This information will remain strictly confidential. If you doubt it will remain confidential, please provide the information you feel comfortable to disclose. As mentioned above, please direct responses to me personally and at your earliest convenience. I intend to produce a summary (which does not divulge the company/institution information in the previous paragraph) which discusses the software maintenance tools, their advantages and disadvantages, and some of my thoughts on the matter. Upon receipt of your response to my article, I will personally acknowledge your request. Thanks in advance to those who opt to participate in my study. -- George Thiruvathukal Laboratory for Parallel Computing and Languages Illinois Institute of Technology Chicago ------------------------------------------------------------------------------ Date: 6 Jul 91 19:48:27 GMT From: jfarrell@jf.Eng.Sun.COM (Jerry Farrell) Subject: Re: initialization questions In article <3815@charon.cwi.nl> guido@cwi.nl (Guido van Rossum) writes: I too was delighted with the first number of the M3 newsletter, but found the suggested workaround for initializing objects somewhat distasteful. An alternative technique we found very useful in the NeWS toolkit's classing scheme may be of interest; it is somewhat out of the current style of M3, but (as far as I can see) should do no violence to the langauge, and would provide a cleaner model at very little implementation or runtime cost. We added several no-op methods to th root class of our system (Object to us, ROOT and UNTRACED ROOT to M3). Two of interest are Init and Destroy. The first is invoked just before New returns. That is, New saves a reference to the new instance, and sends Init to it. This is always safe, since, if no subclass has defined Init, the backstop in Object executes and returns immediately. If some subclass has special pro- cessing it wants done, it will get its crack first. Every class which defines Init is expected to send Init to [invoke Init in] its Parent. Eventually, Init returns to New, which returns the now-initialized object. Destroy is invoked as the system realizes it is about to garbage-collect an object. (The mechanics are a little weird -- tnt uses a 2-level ref-counting scheme for its memory management -- but I think that's not relevant here.) This gives the object a chance to break circular links, and, more relevant to this forum, to un-register itself as a client of various global services (damage, focus management, selection transfers, UI function keys, ...). Closing open files, restoring global data to consistent states, and similar termination processing come to mind. It seems to me it would be a bigger change to the language definiiton than to its implementation, to add some default methods like these to M3's ROOT objects, along with rules about when they are called (at the completion of NEW; at the beginning of garbage collection). It should be statically determinable that a particular object is calling only the no-op backstop in ROOT, and elide the call entirely in compilation. (Well, I'm ready to be corrected by an expert on that. But could the cost be worse than a single runtime check?) There is a little name-space interference, but no worse than "initCalled" variables in objects scattered throughout the world. And it avoids the nearly-universal C problem of requiring everybody to test an error condition (e.g. error return from write(2) ) when nearly nobody does. That route (the suggestion in the newsletter) really seems like a bad step back into the bad old days. jf ------------------------------------------------------------------------------ Date: 6 Jul 91 21:11:57 GMT From: jfarrell@jf.Eng.Sun.COM (Jerry Farrell) Subject: reference cleanup In a recent posting, I mentioned in passing a technique which the NeWS toolkit has found useful for structuring its window system, namely a set of independent services for which clients register. (These include Damage, Focus, selection-making & -transferring, etc.) Typically, a client registers itself with a service; the service maintains a global interest (or one which spans all its clients -- easy in NeWS) in events which may indicate start of a transaction in its specialty, and then determines the particular client affected. This means there are daemonic threads in the system that have references to objects which may go away spontaneously. The desired behavior is that the services then simply remove their references. But this is difficult to arrange in a garbage collected system -- getting the alert back to the service that an object is moribund seems to require some kind of ad-hocery; a Destroy method such as I mentioned in my previous posting can't be relied on, since it won't be called while the service still holds a reference. I am curious what would be considered a proper way to handle this situation in M3. For comparison, the tnt approach relies on a two-level reference scheme in the underlying server: references are either hard (default) or soft. When an object's hard references go to 0, and soft references remain, the system emits an Obsolete event identifying the object affected (with a soft reference, of course;^). Services and the like keep their client lists as soft references, and maintain an interest in Obsolete events. [Actually, they simply declare themselevs as clients of an Obsolete service, but that's gilding the gargoyle.] So the services get notified when one of their clients goes obsolete; they clean out their refs to the client; and that in turn makes it *really* unreferenced, and available for garbage collection. Have others in the M3 world encountered similar situations? How have you approached them? jf ------------------------------------------------------------------------------ Date: Sat, 6 Jul 91 22:37:54 PDT From: Subject: Re: reference cleanup Here are some comments on the suggestions from Guido van Rossum and Jerry Farrell about M3 object initialization and cleanup. Farrell suggests an init method as part of the ROOT object type, which is automatically called when an object is allocated and can be overridden as appropriate for any particular object type. But the current M3 convention allows arguments to be passed to the init method, which this scheme does not. Also, this scheme does not repeat not guarantee that an object's init method will be called: when the implementer of a subtype AB of A overrides the init method, he might erroneously forget to call the supertype init method. Therefore the proposed language change isn't really any different from the current convention: clients are supposed to initialize objects that they allocate, but there is no guarantee. If the implementer of type A wants to protect himself against his client's failure to call his init method, he must keep track of initialization information in the object state, anyway. So the current convention seems to be just as good as the suggested language change. By the way, in practice it is rarely necessary to use an boolean "initialized" field. Usually some other field value can signal an uninitialized object, often without adding any code to the fast path that uses the object. For example, in the implementation of Writers described in "Systems Programming with Modula-3", the fields wr.next and wr.stop have the default value NIL. Therefore in a newly allocated writer, wr.next = wr.stop, which is the condition that causes PutChar to take the slow path. The slow path discovers that wr.next=wr.stop=NIL, which implies that the writer is uninitialized. No extra space in the writer and no extra instructions on the fast path. Similar tricks work in many other cases. Regarding cleanup: There have been several discussions at SRC about how to register a procedure to be called when an object is garbage-collected. Such a facility is needed for network objects, and would be useful for Trestle (it would Trestle to free an X resource when the application drops all handle the resource). This facility will be provided by runtime interface; no language change is required. Although the interfaces can be quite short, there are some fairly delicate issues of specification and implementation, and the design is not yet fixed. The current design is based on "weak refs" (which I suppose are similar to the "soft" references of NewS described by Farrell). ------------------------------------------------------------------------------ Date: Sun, 7 Jul 91 14:15:31 PDT From: muller@src.dec.com (Eric Muller) Subject: archive of comp.lang.modula3 on gatekeeper renamed $ ftp gatekeeper.dec.com Connected to gatekeeper.dec.com. 220 gatekeeper.dec.com FTP server (Version 5.64 Sun Mar 31 13:37:27 PST 1991) r eady. Name (gatekeeper.dec.com:): anonymous Password (gatekeeper.dec.com:anonymous): 331 Guest login ok, send ident as password. 230 Guest login ok, access restrictions apply. ftp> cd pub/DEC/Modula-3/comp.lang.modula3 250 CWD command successful. ftp> dir 200 PORT command successful. 150 Opening ASCII mode data connection for /bin/ls. total 542 -r--r--r-- 1 root system 9154 Jul 7 10:48 89-12.Z -r--r--r-- 1 root system 41743 Jul 7 10:48 90-01.Z -r--r--r-- 1 root system 2256 Jul 7 10:48 90-02.Z -r--r--r-- 1 root system 21440 Jul 7 10:48 90-03.Z -r--r--r-- 1 root system 32745 Jul 7 10:48 90-04.Z -r--r--r-- 1 root system 8887 Jul 7 10:48 90-05.Z -r--r--r-- 1 root system 57987 Jul 7 10:48 90-06.Z -r--r--r-- 1 root system 32653 Jul 7 10:48 90-07.Z -r--r--r-- 1 root system 30358 Jul 7 10:48 90-08.Z -r--r--r-- 1 root system 31680 Jul 7 10:48 90-09.Z -r--r--r-- 1 root system 18891 Jul 7 10:48 90-10.Z -r--r--r-- 1 root system 30292 Jul 7 10:48 90-11.Z -r--r--r-- 1 root system 35720 Jul 7 10:48 90-12.Z -r--r--r-- 1 root system 26209 Jul 7 10:48 91-01.Z -r--r--r-- 1 root system 51772 Jul 7 10:48 91-02.Z -r--r--r-- 1 root system 22931 Jul 7 10:48 91-03.Z -r--r--r-- 1 root system 52578 Jul 7 10:48 91-04.Z -r--r--r-- 1 root system 20443 Jul 7 10:48 91-05.Z -r--r--r-- 1 root system 19692 Jul 7 10:48 91-06.Z -r--r--r-- 1 root system 138 Jul 7 10:48 README 226 Transfer complete. 1270 bytes received in 0.55 seconds (2.3 Kbytes/s) ftp> quit 221 Goodbye. $ -- Eric. ------------------------------------------------------------------------------ Date: 8 Jul 91 01:35:46 GMT From: janssen@parc.xerox.com (Bill Janssen) Subject: Re: initialization questions Yes, I like the approach (adding Initialize() and Finalize() pre-defined methods) you describe. One objection to having an automatic Initialize() that is always mentioned is: The app program needs to be able to pass arguments to Initialize(), such as the stream to be bound, or whatever. If it can't (with the built-in system), then there is no more need for a special initialization than there is for any other type in the system. To my mind this illustrates the need for an Initialize() method for any type allocated with New(), but some people see it differently. Bill -- Bill Janssen janssen@parc.xerox.com (415) 494-4763 Xerox Palo Alto Research Center 3333 Coyote Hill Road, Palo Alto, California 94304 ------------------------------------------------------------------------------ Date: Tue, 9 Jul 1991 10:54:41 PDT From: Norman Ramsey Subject: Re: Modula 3 and C > (1) Are there examples lying about somewhere, showing how to combine > M3 and C? I'm thinking about naming conventions, initialization > procedures, who's in charge of memory allocation, etc. There's a page or two in the installation report. I believe M3 is compatible with C programs that call malloc(), and your C programs can use the RTHeap interface, too. > (2) We've been using a simple exception-handling mechanism (Eric > Roberts' TRY/EXCEPT and TRY/FINALLY macros), which is based on setjmp. > Obviously, we'd like to use the "real" exception mechanism that comes > with M3. Is it conceivable to rewrite Eric's macros to generate the > same code that the M3 compiler would? [Optimal, since the source > (calling) code wouldn't change.] If not, is it conceivable to write > code "by hand" that's the same as (or close enough to) the code that > the M3 compiler generates? Any help on this would be greatly > appreciated. SRC M3 also uses a setjmp mechanism to implement exceptions. The compiler emits C macros to manipulate a stack of exception handlers. You should have little trouble changing the definitions of Eric's macros to use the SRC M3 runtime exception mechanism. If you spend some time studying the generated C code, you should get a pretty good understanding of how to proceed. It won't be great fun, but it's readable enough. Norman Ramsey ------------------------------------------------------------------------------ Date: 10 Jul 91 17:27:24 GMT From: braeu@untadc.enet.dec.com (Walter Braeu) Subject: Some questions Hello m3 fans. I'm rather new to that language and I'm very impressed. However, I've a got couple of questions. - Are there plans to include multiple inheritance? (if not, why not?) - What's the preferred method to write a line to the terminal? I've used Wr.PutText but it seems to write character after character, very slow. I'd like to write the line in one io. - The module Text seems to be a bit incomplete. I don't know if others have come up with a better solution, so I implemented the following: TYPE nextArray = REF ARRAY OF INTEGER; PROCEDURE FindText (s, p: T; start := 0): INTEGER = (*** Knuth Morris (sp?) Pratt algorithm ***) BEGIN IF (s = NIL) OR (p = NIL) OR (start < 0) THEN RETURN -1 END; WITH s_len = NUMBER (s^) - 1, p_len = NUMBER (p^) - 1 DO VAR next: nextArray; i, j: INTEGER; BEGIN next := NEW (nextArray, p_len + 1); i := 0; j := -1; next [0] := -1; REPEAT IF (j = -1) OR (p [i] = p [j]) THEN i := i + 1; j := j + 1; next [i] := j ELSE j := next [j] END UNTIL i >= p_len; i := start; j := 0; REPEAT IF (j = -1) OR (s [i] = p [j]) THEN i := i + 1; j := j + 1 ELSE j := next [j] END UNTIL (j >= p_len) OR (i >= s_len); IF j >= p_len THEN RETURN i - p_len ELSE RETURN -1 END END END END FindText; Walter Walter Braeu walter.braeu@unt.mts.dec.com ------------------------------------------------------------------------------ Date: 10 Jul 91 20:41:35 GMT From: chased@rbbb.Eng.Sun.COM (David Chase) Subject: Re: Some questions braeu@untadc.enet.dec.com (Walter Braeu) writes: > Are there plans to include multiple inheritance? (if not, why not?) I don't know what the current plans are, but back when I was at Olivetti, some of us thought that multiple inheritance was necessary, and some of us tried to figure out how to make it work and/or what it meant. We found that it wasn't as necessary as we thought it was (for defining a compiler's abstract syntax tree), though it would have been nice. In my current work (in C++) I have yet to find a use for multiple inheritance. I'd gladly trade it (especially since I don't use it) for all the other features that Modula-3 has and C++ does not. On the other hand, I came to the conclusion that multiple inheritance has bad interactions with information hiding (that is, opaque supertypes). If you use (in the C++ terminology) "virtual" (shared) base classes, it doesn't work. I'll try to give an example: A / \ B C \ / D A is the base class, and provides some abstract (intended for implementation by subclasses) methods. B and C inherit from A (in ignorance of each other) and both choose to hide their inheritance of A. Both also implement the abstract method "m". Unfortunately, multiple inheritance of B and C by D causes a clash, since method "m" within B and C must have different meanings. (important point follows) This is bad because no single programmer (author of B, author of C, or author of D) will receive any indication that this bad interaction could occur. I spent some time trying to resolve this problem, but never had enough time and patience to devise a solution (assuming one exists) that was simple and consistent and robust in the face of partial revelations and inheritance from different revelations of the same type, etc. The other choice is to adopt "unshared" inheritance. One attack on the problem that I did not pursue to completion is to adopt a WYSIWYG approach with respect to sharing -- if the sharing isn't visible at the object type definition, then it doesn't happen. In the example above, the definition of D cannot see that B and C could share A, so in fact they do not. But -- what happens given other revelations of B and C? What about conflicts? Eiffel contains some solutions to some of these problems, but I'm not sure how well they'd mesh with Modula-3. Anyhow, that's where I left it. I'd be thrilled if someone was able to figure out if and how it would really work, though given my current experience I think there are more important things to work on. David Chase Sun ------------------------------------------------------------------------------ Date: Wed, 10 Jul 1991 17:11:54 PDT From: Norman Ramsey Subject: A comment about the SRC m3 driver I liked it better when the driver used Foo_i.c as the generated C file for Foo.i3 (or Foo.ic), because then I could refer to file Foo_i.c in the debugger (dbx). Now I'm stuck with names like l002340523405.c, and this makes life less pleasant. Can we go back to the old way? Norman Ramsey nr@princeton.edu ------------------------------------------------------------------------------ Date: 7 Jul 91 15:24:48 GMT From: moss@cs.umass.edu (Eliot Moss) Subject: Re: reference cleanup I have comments on both initialization and finalization: Initialization: As I see it, the real problem is that anybody can invoke NEW on any type, and thus avoid initialization. The ideal abstract data type would prevent this. My suggestion is to disallow NEW on opaque types is scopes where the definitive revelation is not visible. In a sense we'd *really* like NEW to be a method, but this gives the same effect with only a slight change to the language and existing compilers. A weaker alternative is for a compiler to emit a warning message when NEW is done in the bad situations. Note also that if we're not dealing with an opaque type, then we can't make very many guarantees about the states of objects/variables anyway, so trying to insert rules about NEW is of limited use. Finalization: While weak references and finalization have some synergy, they are independent features. Weak references insure that a garbage collector will treat something as unreachable and collect it in circumstances that strong references will not. This is clearly useful. Finalization allows something to be done when an object is about to be collected, and it is also useful, but there are certainly cases where finalization is useful without weak references and vice versa. I will also mention that Rick Hudson of UMass is working on a model of finalization for our portable gc toolkit. We expect this will be offered with GNU Modula-3, at least as an option. Rick is working on a position paper he plans to submit to the OOPSLA gc workshop. I'll think about weka refs some more in our context and see what I can come up with. -- J. Eliot B. Moss, Assistant Professor Department of Computer and Information Science Lederle Graduate Research Center University of Massachusetts Amherst, MA 01003 (413) 545-4206, 545-1249 (fax); Moss@cs.umass.edu ------------------------------------------------------------------------------ Date: Wed, 10 Jul 91 17:31:45 PDT From: muller@src.dec.com (Eric Muller) Subject: Re: A comment about the SRC m3 driver In article <91Jul10.171205pdt.34@worsel.parc.xerox.com>, Norman Ramsey writes: > I liked it better when the driver used Foo_i.c as the generated C file > for Foo.i3 (or Foo.ic), because then I could refer to file Foo_i.c in > the debugger (dbx). Now I'm stuck with names like l002340523405.c, and > this makes life less pleasant. Can we go back to the old way? What about the following: if the compilation target is the C file, the compiler generates #line "Foo.ic". If the target is the object, it generates #line "Foo.i3". Does that solve your problem ? -- Eric. ------------------------------------------------------------------------------ Date: 8 Jul 91 13:03:35 GMT From: moss@cs.umass.edu (Eliot Moss) Subject: Re: initialization questions Let's take one more whack at this. A single, fixed interface, Initialize simply will not work, since building some kinds of objects really does require additional arguments to the creation function. What we need is true data abstraction, where you MUST call routines of the abstract data type, passing any required argument, to obtain any object of the type. These routines can guarantee proper initialization. I reiterate that the real problem is that NEW breaks abstraction. I also repeat my suggestion for how to address the problem: outlaw (or at least warn) when NEW is used on an opaque (as opposed to fully revealed) type. In the cases where you're trying to do proper data abstraction, you'll use opaque types, and NEW should be used only in the scope of the definitive revelation of the type (i.e., where you know how it's really implemented). To make things easier in a hierarchy, creation and initialization may be separated, so that creation is used only with exact type in question, but initialization is available to subtypes. (Ideally we'd like it available ONLY to subtypes, but I suspect it's not a big problem.) Just as there may be a number of creation routines, there may be a number of initialization routines, if only because some types have "multiple representations", i.e., distinct representations for different cases, e.g., the empty set, a singleton set, a multiple element set, etc. Even if different representations are not involved, one still may wish to create empty and singleton sets (for example) and this requires different creation and different initialization. I think that trying to legislate having subtypes call supertype Initialize routines won't work out because of the variety I described. Type documentation and implementation conventions may be the answer to reduce implementation errors. I think the conventions work out reasonably well in Smalltalk, for example ..... -- J. Eliot B. Moss, Assistant Professor Department of Computer and Information Science Lederle Graduate Research Center University of Massachusetts Amherst, MA 01003 (413) 545-4206, 545-1249 (fax); Moss@cs.umass.edu ------------------------------------------------------------------------------ Date: 11 Jul 91 01:45:06 GMT From: chased@rbbb.Eng.Sun.COM (David Chase) Subject: Re: initialization questions moss@cs.umass.edu writes: >... I also repeat my suggestion for how to address the >problem: outlaw (or at least warn) when NEW is used on an opaque (as opposed >to fully revealed) type. In the cases where you're trying to do proper data >abstraction, you'll use opaque types, and NEW should be used only in the scope >of the definitive revelation of the type (i.e., where you know how it's really >implemented). What do you about objects with opaque supertypes? The "definitive revelation" of such an object still contains an opaque type within it. One easy way to subvert the "no new of an opaque type" restriction (if you make that an error) is simply (pardon my rusty syntax): TYPE subversive = opaque OBJECT END; I think these things can be enforced only by convention; it seems very difficult to get a guarantee. David Chase Sun ------------------------------------------------------------------------------ Date: 11 Jul 91 04:31:18 GMT From: jfarrell@jf.Eng.Sun.COM (Jerry Farrell) Subject: Re: initialization questions Granted, Initialize needs arguments. My first thought was it should be passed the arglist passed to New. As a blue-sky interface, I still like it -- I think it puts the data where it belongs -- but it runs afoul of 2.6.9, which restricts the arglist to Type plus Bindings. I don't understand what's behind that restriction, so I won't argue it here. Granted, Initialize as defined in the object's base type is not guaranteed to be called; in this respect my original proposal does not differ from the newsletter code. I do not think this is a real issue. (I believe Moss agrees, in saying > I think that trying to legislate having subtypes call supertype Initialize > routines won't work out because of the variety I described.) To restate the argument, sometimes we really want the subclass to ammend by substitution, not addition, and this can only be done by refusing to do the "super send" (= Parent.foo(...) ). Or have I stood your position on its head, Elliot? I believe that the desirable guarantee is that the leaf-type's Initialize (with appropriate arguments) will be invoked for every object (instance). I think this is an appropriate approach to Moss' requirement that > you MUST call routines of the abstract data type, passing > any required argument, to obtain any object of the type. I admit I don't follow the ramifications of Moss' prohibition against NEW on an opaque type. Let me be clearer about my objections to the state of affairs sketched in the newsletter. In descending order of concern: 1) Naively, any code which depends on initialization must test that the initialization has been done. This can be a significant penalty for high-frequency, fast-track operations. Clever coding can sometimes avoid the penalty; but cleverness must be ad-hoc, which I've found has a habit of backfiring after a while. 2) Naively, it requires an extra boolean in every instance which requires initialization; this may be a significant storage cost. Again, ad-hoc cleverness may find another variable or combination which can be semantically overloaded; but again, such cleverness has proved dangerous in my experience. 3) Client programmers are faced with an asymmetry which invites errors: in some cases they simply code "... NEW(Class, ...)"; in others they must use "...NEW(Class).init(...)". They have to go back to the doc/ interface for Class to get it right. A different design would simplify life. ------------------------------------------------------------------------------ Date: Wed, 10 Jul 1991 22:38:22 PDT From: Mark_Weiser.PARC@xerox.com Subject: Re: reference cleanup I suppose this is obvious, but perhaps it needs stating. I'm sure someone will disagree. Yes, weak references and finalization are independent features. They are also not language issues. Both can easily be expressed and implemented in existing m3. -mark ------------------------------------------------------------------------------ Date: 11 Jul 91 13:33:33 GMT From: moss@cs.umass.edu (Eliot Moss) Subject: Initialization (again) Jerry Farrell suggested that there are occasions when a subtype may wish to entirely replace the supertype's Initialize, which strengthens the argument about not legislating that Initialize be called. I would say that if the supertype is opaque (which is the sort of thing I presume Alan Snyder would prefer, based on his OOPSLA '86 paper), then you really can't do such substitutions. But we basically agree that while there is a definite style in mind, a language rule is probably not going to work to achieve it. David Chase points out that my naive rule (outlawing NEW on opaque types) somewhat breaks down when there are opaque supertypes that have subtypes. He gave an example like this: TYPE transparent = opaque OBJECT END; We'd have to allow NEW on this type. The reason is that we'd like to allow opaque supertypes (they appear to increase abstraction), so the rule I gave would have to apply to the last OBJECT .. END in a type. David quite rightly points out that the above idiom allows easy subversion of encapsulation. That may be true, but you'd pretty much have to do it intentionally, and if the supertype is well designed there should be little motivation for this kind of intentional subversion. I *am* grateful to David for taking the time to think about it and pointing out subtleties that had not yet occurred to me. What I am advocating (and this is relevant to the examples Jerry gave at the end of a recent posting, comparing NEW(type, ...) versus NEW(type).Init(...)) is that USERS of an abstract type should never invoke NEW directly; the type should provide appropriate procedures for creating and returning instances, and NEW should be used only within the type's methods. The rule I suggested reinforces and tends to lead towards this style. We can't legislate proper data abstraction, but we can encourage people towards good practices, can't we? -- J. Eliot B. Moss, Assistant Professor Department of Computer and Information Science Lederle Graduate Research Center University of Massachusetts Amherst, MA 01003 (413) 545-4206, 545-1249 (fax); Moss@cs.umass.edu ------------------------------------------------------------------------------ Date: Thu, 11 Jul 1991 14:42:35 PDT From: Norman Ramsey Subject: Re: A comment about the SRC m3 driver > > I liked it better when the driver used Foo_i.c as the generated C file > > for Foo.i3 (or Foo.ic), because then I could refer to file Foo_i.c in > > the debugger (dbx). Now I'm stuck with names like l002340523405.c, and > > this makes life less pleasant. Can we go back to the old way? > What about the following: if the compilation target is the C file, the > compiler generates #line "Foo.ic". If the target is the object, it > generates #line "Foo.i3". Does that solve your problem ? It doesn't solve the problem. I have yet to find a debugger that respects the #line pragmas for purposes of naming compilation units (i.e. files). Indeed, since most C compilation units contain lines from many different source files, it seems unreasonable to ask the debugger to pick one to name the compilation unit. Most debuggers do respect #line pragmas for purposes of printing source code. Norman ------------------------------------------------------------------------------ Date: Fri, 12 Jul 1991 12:57:09 -0500 (CDT) From: Dick Orgass Subject: Re: A comment about the SRC m3 driver Excerpts from m3: 11-Jul-91 Re: A comment about the SRC.. => m3@??? (906) > I have yet to find a debugger that > respects the #line pragmas for purposes of naming compilation units > (i.e. files). Indeed, since most C compilation units contain lines > from many different source files, it seems unreasonable to ask the > debugger to pick one to name the compilation unit. Most debuggers do > respect #line pragmas for purposes of printing source code. I must admit that I'm rather surprised that this is the case. I've been using Modula-3 with four different dbx implementations (AIX 3.1, AOS 4.3 and 2 for AIX PS/2) and all of them work as expected for Modula-3 source file names, *.[im]3, when used with the SRC system (including naming compilation units). Dick ------------------------------------------------------------------------------ Date: 12 Jul 91 19:10:39 GMT From: harbison@bert.pinecreek.com (Sam Harbison) Subject: Re: multiple inheritance (was Re: Some questions) Regarding the usefulness of multiple inheritance, see T. A. Cargill's article in Computing Systems 4(1) (Winter, 1991) [a USENIX publication?], "Controversy: The Case Against Multiple Inheritance in C++." Cargill looks at published examples of MI in C++ and experience in other languages. (Although experiences with other languages, he says, is not necessarily relevant.) He finds that many MI examples are aggregation disguised as inheritance, and others can be rewritten without MI. Conclusion: "The evidence to date is that multiple inheritance is not useful in writing C++ programs. It should not become part of the ANSI C++ standard before convincing examples of its use are published. If multiple inheritance is a mistake, programmers will pay the price of using an unnecessarily complicated language for years to come." Sam Harbison Pine Creek Software; 305 S. Craig St., Suite 300; Pittsburgh, PA 15213 +1 412 681 9811; harbison@bert.pinecreek.com ------------------------------------------------------------------------------ Date: Fri, 12 Jul 91 13:54:11 PDT From: Subject: Re: Initialization (again) Should NEW automatically call the init method of the newly allocated object (hereinafter called "auto-init")? The status quo says "no", which I will argue is correct. If you are implementing an opaque object type, you have a choice of several methods to try to ensure that all objects of your type are properly initialized. Method 0: make your type an opaque subtype of REFANY and export a "New" procedure for the type: INTERFACE I; TYPE T <: REFANY; PROCEDURE New(...): T END I. This gives you complete control: no client can produce a T except by calling New, and you control the implementation of New, which can initialize the object properly. A client can't allocate a T with the language primitive NEW, since T is only revealed to be a subtype of REFANY. Eliot Moss seems to be leaning towards method 0 in his recent posting; notice that is available without any language change. Notice also that if you use method 0, auto-init doesn't matter to you. The trouble with method 0 is that the client can't declare a subtype of T. If this matters, you have to do something else. Method 1: give your type an init method and specify in the interface that clients that allocate an object of your type must call the init method, and that all bets are off if they fail in this obligation. Method 1 is fine as long as your clients are infallible. But if your clients are fallible, method 1 is very error prone. At first it seems like auto-init would make make method 1 safe even with fallible clients, but this is an illusion: NEW automatically calls the subtype init method, but if client are fallible, then there is no guarantee that the subtype init method calls the supertype init method. So if you use method 1, auto-init again doesn't matter to you. (Simula provides an auto-init feature in which the caller of NEW provides arguments for ALL the init methods, of the object and its supertype and its super-supertype, ..., which NEW calls in a fixed order. The troubles with this are (1) you often need more flexibility as far as the order in which the init methods are executed, and (2) with opaque supertypes, there is no way for the caller of NEW to know what arguments to supply for the supertype init method.) Method 2: use default field values to guarantee that objects of your type are properly initialized, even if your init method is never called. This is safe even if clients are fallible, since the M3 runtime initializes the field values as part of the call to NEW. If you use method 2, auto-init again doesn't matter to you. The method recommended by Sam Harbison in the Modula-3 newsletter is a special case of method 2 (hereinafter called method 2A) in which a boolean field "initialized" is added to the state, which defaults to false. The various operations all test this boolean, and if it is false, then they initialize the object before continuing. The trouble with method 2a is that it costs instructions to test the "initialized" boolean. If this matters, you have to use method 2b, in which you find a representation for a newly-allocated object that does not cost any extra instructions for common cases. For example if you want the fast path through Wr.PutChar(wr, ...) to be only a few instructions long, you arrange that the condition for taking the fast path is wr.next # wr.stop, and make the initial values of wr.next and wr.stop both be NIL. This guarantees that PutChar to an uninitialized writer will take the slow path, without costing any extra instructions for the test. The trouble with method 2b is that it requires you to think. Each method has its advantages and disadvantages, but the existing language allows you to choose. No matter which method you use, the auto-init language feature doesn't help. The only advantage of auto-init is that it allows you to write NEW(T, args) whereas with the existing language you have to write NEW(T).init(args) at a cost of five extra characters. There is also a cost to auto-init, since the existing language allows you to override field or method values by providing extra arguments to NEW. This would have to be given up for auto-init, or else some other syntax would have to be invented. The knee-jerk reaction of almost every good programmer is to favor auto-init, because experience teaches that initialization errors are common and the more the language can do to make them uncommon or impossible, the better. (In any case, my first reaction was to favor it.) But the detailed analysis leads to a different conclusion. Greg ------------------------------------------------------------------------------ Date: 13 Jul 91 19:00:50 GMT From: moss@cs.umass.edu (Eliot Moss) Subject: Re: Initialization (again) Yes, I suppose you could say that I do more or less favor Greg's Method 0, except that I'd like to guarantee proper creation of abstract OBJECT types. I agree that once you allow clients to create subtypes, all bets are off. I guess the distinction I make is between "ordinary client", who just use a type, and "extending clients", who create subtypes. It is reasonable to expect an extending client to have to be more careful, since they are helping to implement a type rather than just using it. The main thing I would like to promote is the notion that (ordinary) clients should not NEW abstract types directly, but should use creation procedures/methods supplied by the type in question. Extending clients naturally DO need to NEW, and USUALLY should call the supertype init as well. If we develop, publicize, and promote an appropriately safe coding style, then we will do a lot to avoid the errors we're concerned about. The error message I proposed in previous postings is just a partial safety net, to catch some oversights. -- J. Eliot B. Moss, Assistant Professor Department of Computer and Information Science Lederle Graduate Research Center University of Massachusetts Amherst, MA 01003 (413) 545-4206, 545-1249 (fax); Moss@cs.umass.edu ------------------------------------------------------------------------------ Date: 15 Jul 91 23:09:46 GMT From: fraley@aspen.IAG.HP.COM (Bob Fraley) Subject: Re: Re: multiple inheritance (was Re: Some questions) It is no doubt that there are many ways of abusing multiple inheritance. However, if multiple inheritance solves real problems that cannot be solved well some other way, then it (or a safer variant of it) should be included in an advanced langauge. In the work that I've been doing, multiple inheritance is extremely valuable. Objects which we build must meet a number of standard interfaces. These interfaces are defined by other people, and libraries of these standards are available as C++ abstract classes. A given object inherits a number of these interfaces, and then implements all of the interface functions. There are several important things to notice about this use of multiple inheritance which distinguish it from most of the cited examples: -- The only thing that is inherited is the interface, not the implementation. (Reuse of implementations is still possible, but the implementation structure can be quite different from the interface structure.) -- Inheritance of the interface is important, since an application which uses the object will know about only one of the standard interfaces that was inherited, and will want to communicate with the object using that interface. -- Conventions are used that minimize the risk of duplicate names. When duplicate names are present, they will generally have identical semantics. In addition, interface collision of names is much easier to resolve than implementation collisions. Multiple inheritance seems to be the best way to structure objects in this environment. All of the alternatives which we've discussed here have disadvantages. So multiple inheritance is not all bad. Bob Fraley fraley@iag.hp.com ------------------------------------------------------------------------------ Date: 16 Jul 91 13:52:26 GMT From: wkh@duke.austin.ibm.com Subject: Modules/Objects when and why? A co-worker asked me a question about Modula-3 yesterday that, as a Modula-3 new comer, I found myself unable to answer to either of our satisfaction. He observed that Ada and C++ both have a single abstraction mechanism, packages and classes respectively, whereas Modula-3 appears to have two: modules and objects. Then he asked the obvious question: "so when do I use modules and when do I use objects?" I fumbled with it for a few minutes before confessing that "gee, I don't really know." It seems to me that there is a difference in granularity, i.e. I think of a module as being a "larger" thing than an object; on the other hand objects provide a subtyping mechanism necessary for creating frameworks and doing other useful object-oriented kinds of things. Neither of these observations of the obvious provide any compelling guidelines for using one versus the other though. Could someone enlighten us? ... WkH Ward K Harold (512) 823-4139 [T/L 793-4139] IBM Personal Systems Programming external: wkh@dce.austin.ibm.com 11400 Burnet Rd., Zip 2603 internal: wkh@duke.austin.ibm.com Austin, TX 78758 vnet: wharrold --ausvmq ------------------------------------------------------------------------------ Date: Tue, 16 Jul 1991 14:16:44 PDT From: Norman Ramsey Subject: SRC compiler warnings I just discovered that -w1 is no longer the default, and having discovered it, I have a comment: I think the compiler is too aggressive in announcing functio ns that don't return a value. For example, it complains about the following: PROCEDURE SavedOffset(saved:RegSet; number : RegIndex): INTEGER = VAR offset := 0; BEGIN FOR i := 31 TO 0 BY -1 DO IF i = number THEN RETURN offset; ELSIF i IN saved THEN DEC(offset,4); END; END; END SavedOffset; Since TYPE RegIndex = [0..31], this function always returns a value, and the compiler warning is bogus. If the compiler is not omniscient, I would like to be warned only when the compiler can determine that the function cannot return a value, not when it has determined that it might not return a value. Comments? Norman Ramsey nr@princeton.edu ------------------------------------------------------------------------------ Date: Tue, 16 Jul 91 14:28:19 PDT From: muller@src.dec.com (Eric Muller) Subject: file name lengths. In preparation for a future release of SRC Modula-3, we would like to get a clear picture of the constraints on the length of file names. One constraint we have now is that the interface Foo is stored in a file named "Foo.i3". This constraint will probably be enforced on modules as well (this makes a number of tools easier to write). We currently use 2 characters for extentions (i3, io, m3, mo, ma, soon ix and mx will be added). We could do with one, but I would really prefer to stay with 2. What is the limit we should adopt so that SRC Modula-3 can be easily ported to non-bsd like U**x or even non-U**x operating systems ? Please send your answer to m3-request@src.dec.com, we will summarize. -- Eric. ------------------------------------------------------------------------------ Date: 17 Jul 91 13:20:34 GMT From: moss@cs.umass.edu (Eliot Moss) Subject: Re: Modules/Objects when and why? Well I'll take a quick shot at modules versus objects as structuring mechanisms. In most cases, module, interface, and an object type being defined should or will be one-to-one, i.e., one interface defines one opaque object type, and one module gives the definitive revelation and method implementations. The language gives us additional flexibility, though, which is sometimes important. here are two examples. First, some types may be complex enough (or we may anticipate a rich subtype structure related to varieties of implementation) that they are implemented using more than one layer of revelation. That is, they have an external interface and type for consumers, and a richer one, showing some implementation details, for subtype implementers, and then a collection of specific implementations. Perhaps examples of this come up in IO streams. Hierarchy certainly gives rise to multiple levels of interfaces, and, if one can implement "generic" methods at an abstract level (sometimes called abstract methods), then there is high level code, too. These abstract methods are written to the external (or maybe a richer internal) interface, but will tend to work more through methods than direct manipulation of state, though both can be done. For example, in IO one can have an internal level defining buffering for all buffered input streams, with the details of reading data from the actual data source into the buffer hidden in the implementation of the specific data source. Meanwhile, the buffering is hidden behind an interface so that end users cannot mess with the buffers directly. Another thing that is interesting about M3, which you did not mention, is that interfaces and modules need not be one to one. For example, in implementing geometric concepts such as points, lines, and polygons, we may need to implement several types simultaneously to get effective representations. We could perhaps define their interfaces separately, and then define them in one module. Or we could put all the types in one interface and implement them in one large module. Or structure the interfaces either way, define the representations in an internal interface, and then implement the types in separate modules. Note also that an individual type need not be implemented entirely in one module. Layers of object hierarchy naturally spread the implementation through multiple modules when abstract methods are used, but there are also cases where it is convenient to separate parts of a type's implementation, e.g., machine or OS dependent parts might be separated from the independent parts, to make it easier to configure for a range of systems. I am sure this is not exhaustive, but the flexibility is there for good reason, though the normal case would tend to identify type, interface, and module. -- J. Eliot B. Moss, Assistant Professor Department of Computer and Information Science Lederle Graduate Research Center University of Massachusetts Amherst, MA 01003 (413) 545-4206, 545-1249 (fax); Moss@cs.umass.edu ------------------------------------------------------------------------------ Date: 17 Jul 91 13:25:30 GMT From: moss@cs.umass.edu (Eliot Moss) Subject: Re: SRC compiler warnings I agree that it's annoying to get a message because you did not put in a RETURN statement that would be unreachable anyway, but I much prefer the compiler to err on the side of safety and tell me about the cases it can't figure out instead of the only the ones it can. I would say that if the compiler can prove there are cases when one fails to RETURN, then a stronger message is in order -- an error rather than a warning. In the case you gave, the compiler is not sure, and it should just tell you you MIGHT run off the end of the function (i.e., there MAY be an error). It would be nice, of course, if there were a way to turn the warning off for an individual procedure (perhaps via a pragma) once you've hand verified that everything is all right. That way you don't have useful error messages buried in warning about situations you've determined are really ok. But this is pretty sophisticated ..... -- J. Eliot B. Moss, Assistant Professor Department of Computer and Information Science Lederle Graduate Research Center University of Massachusetts Amherst, MA 01003 (413) 545-4206, 545-1249 (fax); Moss@cs.umass.edu ------------------------------------------------------------------------------ Date: Wed, 17 Jul 91 09:57:34 PDT From: muller@src.dec.com (Eric Muller) Subject: Re: SRC compiler warnings In article , Eliot Moss writes: > It would be nice, of > course, if there were a way to turn the warning off for an individual > procedure (perhaps via a pragma) once you've hand verified that everything is > all right. With SRC Modula-3, if the pragma <*NOWARN*> is present on a source line, warnings on that line won't be emitted. This is a bit dangerous to use as it is not selective about the warnings that are suppressed, but it can be useful in that case. -- Eric. ------------------------------------------------------------------------------ Date: Wed, 17 Jul 91 11:50:10 PDT From: Subject: Re: Modules/Objects when and why? Interfaces and modules provide a mechanism for controlling the set of names and type definitions available to a particular unit of a program. Objects are part of the type system and provide a mechanism for defining and implementing types that have satisfy the subtype relation. In other words, modules are used to control what names are bound, while types (and thus objects) are used to control what values may be taken on by variables. Naming and the type system are related, of course, because types and variables can have names. Your assumption that Ada and C++ have one mechanism that solves both problems is incorrect because - While C++ has a type system it has no real mechanism for controlling the availability of names other than the include files. While include files can be used like modules they are really an "extra-language" mechanism. - Ada has packages for controlling naming and a type system but that type system has no good mechanism for subtyping. [It does have something called 'abstracted types' (is that right? I can't remember the name) that provides something like a subtype relationship but nobody has been able to explain to me how one uses it. (But then again, I haven't been very eager to learn!)] There are languages that put naming control, and thus module functionality, into type system. Pebble (Lampson and ?), Quest (Cardelli) are two developed here where modules are actually typed objects. As Eliot Moss noted, often one uses an interface and a new type, either an object type or not, together, because generally along with defining a type and its operations one wants to give convenient access to their names. However, one can group several types in a single interface or use an interface just to hold a revelation of additional information about another type or set of types. Garret Swart (at SRC but not a member of the Modula-3 committee) ------------------------------------------------------------------------------ Date: 17 Jul 91 19:28:41 GMT From: harbison@bert.pinecreek.com (Sam Harbison) Subject: FIRST applied to REF ARRAY Suppose: VAR s := NEW(REF ARRAY OF INTEGER, 10); Then, I can write "s[i]" instead of "s^[i]", but according to SPwM3 I must write "FIRST(s^)" instead of "FIRST(s)". Since FIRST is not defined on reference types, would it be OK to make FIRST(s) the same as FIRST(s^) in this case? The same change would be needed for LAST and NUMBER. I'm opposed to changing the language, but "clarifications" are always in order... :-) Sam Harbison Pine Creek Software; 305 S. Craig St., Suite 300; Pittsburgh, PA 15213 +1 412 681 9811; harbison@bert.pinecreek.com ------------------------------------------------------------------------------ Date: Wed, 17 Jul 91 14:32:27 PDT From: Subject: Re: SRC compiler warnings It would be nice, of course, if there were a way to turn the [missing RETURN] warning off for an individual procedure (perhaps via a pragma) once you've hand verified that everything is all right. On could simulate such a prgama with <* ASSERT FALSE *>. This solution only requires that the compiler is able to recognize this special case of ASSERT and treat it as a dead end, just like RAISE Foo. With this assumption, Norman could suppress the "missing RETURN" warning in his exemple by writing PROCEDURE SavedOffset(saved:RegSet; number : RegIndex): INTEGER = VAR offset := 0; BEGIN FOR i := 31 TO 0 BY -1 DO IF i = number THEN RETURN offset; ELSIF i IN saved THEN DEC(offset,4); END; END; <* ASSERT FALSE *> END SavedOffset; Note that we must currently use a similar trick to suppress bogus incomplete TYPECASE errors. That is, instead of CASE Random.Integer(NIL) MOD 2 OF | 0 => Wr.PutChar(wr, "heads"); | 1 => Wr.PutChar(wr, "tais"); END we currently have to write CASE Random.Integer(NIL) MOD 2 OF | 0 => Wr.PutChar(wr, "heads"); | 1 => Wr.PutChar(wr, "tais"); ELSE <* ASSERT FALSE *> END --jorge ------------------------------------------------------------------------------ Date: Wed, 17 Jul 91 14:32:44 PDT From: muller@src.dec.com (Eric Muller) Subject: Re: FIRST applied to REF ARRAY In article <1991Jul17.192841.9499@bert.pinecreek.com>, Sam Harbison asks : > Since FIRST is not > defined on reference types, would it be OK to make FIRST(s) the same > as FIRST(s^) in this case? The same change would be needed for LAST > and NUMBER. > > I'm opposed to changing the language, but "clarifications" are always > in order... :-) I would really like to see that change. I can't remember the number of times I forgot to include the stupid ^. -- Eric. ------------------------------------------------------------------------------ Date: Wed, 17 Jul 91 19:47:24 PDT From: Subject: Re: FIRST applied to REF ARRAY, and reserved identifiers Since FIRST is not defined on reference types, would it be OK to make FIRST(s) the same as FIRST(s^) in this case? The same change would be needed for LAST and NUMBER. I'm opposed to changing the language, but "clarifications" are always in order... :-) I would welcome such a clarification, too. 8-) --jorge ------------------------------------------------------------------------------ Date: Thu, 18 Jul 91 20:16:53 +0200 From: rcvie!fs_reich@relay.EU.net (Klaus Reichl) Subject: Modula 3 emacs mode Hi there, We successfully installed SRC Modula 3 at our site, it looks like pretty good work. Is there a modula3 mode for GNUEmacs around somewhere? Thanks for hints, Klaus. -- Klaus Reichl voice: +43 (1) 39 16 21 / 132 Alcatel Austria-ELIN Research Center fax: +43 (1) 39 14 52 Ruthnergasse 1-7 Internet: fs_reich@rcvie.co.at A-1210 Wien UUCP: ...mcsun!tuvie!rcvie!fs_reich Austria/Europe ------------------------------------------------------------------------------ Date: Thu, 18 Jul 91 12:53:27 PDT From: mjordan@src.dec.com (Mick Jordan) Subject: Re: Modula 3 emacs mode I have such a thing, which I will put on gatekeeper in the near future. Meanwhile here it is. ; Modula 3 editing support package ; Author Mick Jordan ; amended Peter Robinson ; ported to GNU Michael Schmidt ;;;From: "Michael Schmidt" ;;;Modified by Tom Perrine (TEP) ;;;Further modified by TMorris ;;;And again to Modula 3 by Mick Jordan ;;; NOTE: To 'byte-compile-file' this, you need: ;;; (setq max-lisp-eval-depth 2000) ;;; (setq max-specpdl-size 2000) ; ; $Revision: 1.10 $ ; ; ; AUTO MODE HANDLING ; (setq auto-mode-alist (cons (cons "\\.i$" 'modula-3-mode) auto-mode-alist)) (setq auto-mode-alist (cons (cons "\\.m$" 'modula-3-mode) auto-mode-alist)) (setq auto-mode-alist (cons (cons "\\.i3$" 'modula-3-mode) auto-mode-alist)) (setq auto-mode-alist (cons (cons "\\.m3$" 'modula-3-mode) auto-mode-alist)) ; ; MODE SYNTAX TABLE (Added by TEP) ; (defvar m3-mode-syntax-table nil "Syntax table in use in Modula 3 mode buffers.") (if m3-mode-syntax-table () (let ((table (make-syntax-table))) (modify-syntax-entry ?_ "w" table) (modify-syntax-entry ?\\ "\\" table) (modify-syntax-entry ?\( ". 1" table) (modify-syntax-entry ?\) ". 4" table) (modify-syntax-entry ?* ". 23" table) (modify-syntax-entry ?\( "() " table) (modify-syntax-entry ?\) ")( " table) (modify-syntax-entry ?\[ "(] " table) (modify-syntax-entry ?\] ")[ " table) (modify-syntax-entry ?{ "(} " table) (modify-syntax-entry ?} ")} " table) (modify-syntax-entry ?+ "." table) (modify-syntax-entry ?- "." table) (modify-syntax-entry ?= "." table) (modify-syntax-entry ?% "." table) (modify-syntax-entry ?< "." table) (modify-syntax-entry ?> "." table) (modify-syntax-entry ?\' "\"" table) (setq m3-mode-syntax-table table))) ; ; MODE KEY MAP (Added by TEP) ; (defvar m3-mode-map nil "Keymap used in Modula 3 mode.") (defun setup-m3-mode-map () "Sets up Modula 3 mode map; this must be called after the sequence for the keypad key \"?\\C-@\" has been setup - it uses \"function-key-sequence\" on that key in order to bind the Modula 3 specific functions" (if m3-mode-map () (let ((map (make-sparse-keymap)) (other-map (make-sparse-keymap))) (define-key map "\^i" 'm3-abbrev-or-tab) (define-key map "\C-ca" 'm3-array) (define-key map "\C-cb" 'm3-block) (define-key map "\C-cc" 'm3-case) (define-key map "\C-cd" 'm3-declare) (define-key map "\C-ce" 'm3-else) (define-key map "\C-cf" 'm3-for) (define-key map "\C-ci" 'm3-if) (define-key map "\C-cm" 'm3-choose-module) (define-key map "\C-cl" 'm3-loop-or-lock) (define-key map "\C-c|" 'm3-next-case) (define-key map "\C-co" 'm3-object) (define-key map "\C-c\C-o" other-map) (define-key map "\C-cp" 'm3-procedure) (define-key map "\C-cr" 'm3-record) (define-key map "\C-ct" 'm3-try-or-typecase) (define-key map "\C-cu" 'm3-until) (define-key map "\C-cw" 'm3-while-or-with) (define-key map "\C-cy" 'm3-import) (define-key map "\C-c{" 'm3-begin-comment) (define-key map "\C-c}" 'm3-end-comment) (define-key other-map "a" 'm3-toggle-abbrev) (define-key other-map "v" 'm3-path-find-file) (define-key other-map "b" 'm3-toggle-buffer) (define-key other-map "c" 'm3-compile) (define-key other-map "p" 'm3-convert-proc-header) (setq m3-mode-map map) ))) ; ; INDENTATION ; (defvar m3-indent 2 "*This variable gives the indentation in Modula 3 Mode") ; ; ROUTINE TO CHECK IF BUFFER CONTAINS DEF MODULE ; (defun m3-is-def () "Does current buffer's name suggest that it contains an interface?" (or (string-equal (m3-get-extension (buffer-name)) ".i") (string-equal (m3-get-extension (buffer-name)) ".i3"))) ; ; THE MAIN ROUTINE - SETS UP MODULA-3 MODE ; (defun modula-3-mode () "This is a mode intended to support program development in Modula 3. All control constructs of Modula 3 can be reached by typing CNTRL C followed (usually!) by the first character of the construct. There is also a pseudo abbrev mode for Modula 3. Typing the first letter(s) of a construct and then hitting TAB will cause the full construct to be inserted. When there is overlap between two constructs (e.g. WITH and WHILE) type the smallest unique substring (e.g. \"wi\" for WITH) then hit TAB. If the character before point is not a letter or the preceding word is not a valid abbreviation TAB just inserts whitespace to the next tab stop. If the abbreviation is not unique alphabetic ordering is used e.g. \"w\" gives WHILE rather than WITH. There are a few mode specific commands which are not to do with inserting text for language structures (e.g. compile module, toggle pseudo abbrev mode). These can be used by typing CTRL-C CTRL-O, \"O\" (for \"Other\") and then the command letter. See the following list for more detailed information. \\{m3-mode-map} The variable m3-indent controls the number of spaces for each indentation." (interactive) (kill-all-local-variables) (setup-m3-mode-map) (use-local-map m3-mode-map) (setq major-mode 'modula-3-mode) (setq mode-name "Modula 3") (make-local-variable 'comment-column) (setq comment-column 41) (make-local-variable 'end-comment-column) (setq end-comment-column 75) (set-syntax-table m3-mode-syntax-table) (make-local-variable 'paragraph-start) (setq paragraph-start (concat "^$\\|" page-delimiter)) (make-local-variable 'paragraph-separate) (setq paragraph-separate paragraph-start) (make-local-variable 'indent-line-function) (setq indent-line-function 'm3-indent-line) (make-local-variable 'require-final-newline) (setq require-final-newline t) (make-local-variable 'comment-start) (setq comment-start "(* ") (make-local-variable 'comment-end) (setq comment-end " *)") (make-local-variable 'comment-column) (setq comment-column 41) (make-local-variable 'comment-start-skip) (setq comment-start-skip "/\\*+ *") (make-local-variable 'comment-indent-hook) (setq comment-indent-hook 'c-comment-indent) (make-local-variable 'parse-sexp-ignore-comments) (setq parse-sexp-ignore-comments t) (run-hooks 'm3-mode-hook)) ; ; FORMATTING ; (defun m3-newline () "Insert a newline and indent following line like previous line." (interactive) (let ((hpos (current-indentation))) (newline) (indent-to hpos))) (defun m3-tab () "Indent to next tab stop." (interactive) (indent-to (* (+ (/ (current-column) m3-indent) 1) m3-indent))) (defun m3-indent-line () "Indent following line like previous line - needs work." (interactive) (let ((hpos nil)) (save-excursion (previous-line 1) (setq hpos (current-indentation))) (indent-to hpos))) ; ; COMMENTS ; (defun m3-begin-comment () "Indent to start comment column and then start Modula 3 comment." (interactive) (if (not (bolp)) (indent-to comment-column 0)) (insert "(* ")) (defun m3-end-comment () "Indent to end comment column and then end Modula 3 comment." (interactive) (if (not (bolp)) (indent-to end-comment-column)) (insert "*)\n")) (defun m3-banner () "Insert a comment line suitable for marking the start of a big comment." (insert "(******************************************************************* ********)\n")) ; ; STATEMENTS, DECLARATIONS AND KEYWORDS ; (defun m3-array () "Insert ARRAY, prompt for index type then finish with OF." (interactive) (insert "ARRAY ") (insert (read-string "Index type: ")) (insert " OF ")) (defun m3-case () "Build skeleton CASE statement, prompting for the expression and first label( s)." (interactive) (insert "CASE ") (insert (read-string "Case expression: ") " OF") (m3-newline) (insert "| ") (insert (read-string "First case label(s): ") " =>") (m3-newline) (m3-newline) (insert "END; (* case *)") (end-of-line 0) (m3-tab) (m3-tab)) (defun m3-const () "Insert CONST then newline and tab." (interactive) (insert "CONST") (m3-newline) (m3-tab)) (defun m3-declare () "Insert a Modula 3 declaration; prompt the user for declaration type." (interactive) (message "Var (default), Const, Type, Exception or Procedure") (let ((choice (read-char))) (if (char-equal ?c choice) (m3-const) (if (char-equal ?t choice) (m3-type) (if (char-equal ?e choice) (m3-exception) (if (char-equal ?p choice) (m3-procedure) (m3-var))))))) (defun m3-except () "Insert EXCEPT clause of a TRY statement." (interactive) (insert "EXCEPT") (m3-newline) (m3-newline) (insert "END; (* try *)") (end-of-line -2) (m3-tab)) (defun m3-exception () "Insert EXCEPTION then newline and tab." (interactive) (insert "EXCEPTION") (m3-newline) (m3-tab)) (defun m3-else () "Insert ELSE or ELSIF keyword and indent for next line." (interactive) (m3-newline) (backward-delete-char-untabify m3-indent ()) (message "elsE (default) or elsIf") (if (not (char-equal ?i (read-char))) (insert "ELSE") (insert "ELSIF ") (insert (read-string "Elsif expression: ")) (insert " THEN")) (m3-newline) (m3-tab)) (defun m3-finally () "Insert FINALLY clause of a TRY statement." (interactive) (insert "FINALLY") (m3-newline) (m3-tab) (m3-newline) (backward-delete-char-untabify m3-indent ()) (insert "END; (* try *)") (end-of-line -2) (m3-tab)) (defun m3-for () "Build skeleton FOR loop statement, prompting for the loop parameters." (interactive) (insert "FOR ") (insert (read-string "For: ") " TO ") (insert (read-string "To: ")) (let ((by (read-string "By: "))) (if (not (string-equal by "")) (insert " BY " by))) (insert " DO") (m3-newline) (m3-newline) (insert "END; (* for *)") (end-of-line 0) (m3-tab)) (defun m3-if () "Insert skeleton IF statement, prompting for the expression." (interactive) (insert "IF ") (insert (read-string "If expression: ") " THEN") (m3-newline) (m3-newline) (insert "END; (* if *)") (end-of-line 0) (m3-tab)) (defun m3-loop-or-lock () "Insert LOOP or LOCK statement; prompt user to decide which." (interactive) (message "looP (default) or locK") (if (char-equal ?k (read-char)) (m3-lock) (m3-loop))) (defun m3-loop () "Build skeleton LOOP (with END)." (interactive) (insert "LOOP") (m3-newline) (m3-newline) (insert "END; (* loop *)") (end-of-line 0) (m3-tab)) (defun m3-lock () "Build skeleton LOCK (with END)." (interactive) (insert "LOCK ") (insert (read-string "Lock mutex: ") " DO") (m3-newline) (m3-newline) (insert "END; (* lock *)") (end-of-line 0) (m3-tab)) (defun m3-module-type () "Returns char describing module type deduced from buffername and user input." (interactive) (if (m3-is-def) ?i ?m)) (defun m3-choose-module () "Build skeleton MODULE, decide module type from buffername and user input." (interactive) (m3-module (m3-module-type))) (defun m3-choose-module-name () "Prompt user for module name; if user returns null use buffer name." (let ((name (read-string "Module name (default is buffer name): "))) (if (string-equal name "") (m3-strip-extension (buffer-name)) name))) (defun m3-module (type) "Build skeleton MODULE, prompting for module name." (interactive) (if (char-equal type ?i) (insert "INTERFACE ") (if (char-equal type ?m) (insert "MODULE ") ())) (let ((name (m3-choose-module-name)) (args "")) (insert name) (if (char-equal type ?m) (setq args (read-string "Exports list (default is empty): ")) ()) (if (not (string-equal args "")) (insert " EXPORTS " args)) (insert ";\n\n") (if (char-equal type ?m) (insert "BEGIN\n\nEND " name ".\n") (insert "END " name ".\n")) (if (char-equal type ?m) (previous-line 5) (previous-line 3)) )) (defun m3-next-case () "Move on to next arm of a CASE or TYPECASE statement." (interactive) (m3-newline) (backward-delete-char-untabify m3-indent) (backward-delete-char-untabify m3-indent) (let* ((label (read-string "Case label(s): ")) (not-else (not (string-equal "ELSE" label)))) (if not-else (insert "| ")) (insert label) (if not-else (insert " =>")) (m3-newline) (m3-tab) (if not-else (m3-tab)))) (defun m3-object () "Insert a skeleton OBJECT." (interactive) (insert "OBJECT") (m3-newline) (m3-newline) (insert "METHODS") (m3-newline) (insert "END; (* object *)") (end-of-line -1) (m3-tab)) (defun m3-procedure () "Build a skeleton PROCEDURE declaration, prompting the user as necessary." (interactive) (insert "PROCEDURE ") (let ((name (read-string "Procedure name: " )) args) (insert name "(") (insert (read-string "Procedure arguments: ") ")") (setq args (read-string "Procedure result type: ")) (if (not (string-equal args "")) (insert ": " args)) (setq args (read-string "Procedure raises list (or ANY): ")) (if (not (string-equal args "ANY")) (insert " RAISES {" args "}")) (if (m3-is-def) (insert ";") (insert "=")) (m3-newline) (if (m3-is-def) () (m3-tab) (insert "BEGIN") (m3-newline) (m3-newline) (insert "END ") (insert name) (insert ";\n\n") (end-of-line -2) (m3-tab)))) (defun m3-block () "Insert a skeleton block" (interactive) (insert "BEGIN") (m3-newline) (m3-newline) (insert "END;") (end-of-line 0) (m3-tab)) (defun m3-record () "Insert a skeleton RECORD." (interactive) (insert "RECORD") (m3-newline) (m3-newline) (insert "END; (* record *)") (end-of-line 0) (m3-tab)) (defun m3-type () "Insert TYPE then newline and tab." (interactive) (insert "TYPE") (m3-newline) (m3-tab)) (defun m3-try-or-typecase () "Insert a TRY or TYPECASE statement; prompt the user to decide which." (interactive) (message "tRy (default) or tYpecase") (if (char-equal ?y (read-char)) (m3-typecase) (m3-try))) (defun m3-try () "Build TRY statement, prompting to see if it is the EXCEPT or FINALLY form." (interactive) (insert "TRY") (m3-newline) (m3-newline) (message "Except (default) or Finally") (if (char-equal ?f (read-char)) (m3-finally) (m3-except))) (defun m3-typecase () "Build skeleton TYPECASE statement, prompting for the expression and first la bels." (interactive) (insert "TYPECASE ") (insert (read-string "Typecase expression: ") " OF") (m3-newline) (insert "| " (read-string "First typecase label(s): ") " =>") (m3-newline) (m3-newline) (insert "END; (* typecase *)") (end-of-line 0) (m3-tab) (m3-tab)) (defun m3-until () "Insert a skeleton REPEAT loop, prompting the user for the final expression." (interactive) (insert "REPEAT") (m3-newline) (m3-newline) (insert "UNTIL ") (insert (read-string "Until expression: ") ";") (end-of-line 0) (m3-tab)) (defun m3-var () "Insert VAR then newline and tab." (insert "VAR") (m3-newline) (m3-tab)) (defun m3-while-or-with () "Insert WHILE or WITH statement; prompt user to decide which." (interactive) (message "wHile (default) or wIth") (if (char-equal ?i (read-char)) (m3-with) (m3-while))) (defun m3-while () "Insert skeleton WHILE statement; prompt user for while expression." (interactive) (insert "WHILE ") (insert (read-string "While expression: ")) (insert " DO") (m3-newline) (m3-newline) (insert "END; (* while *)") (end-of-line 0) (m3-tab)) (defun m3-with () "Insert skeleton WITH statement; prompt user for WITH bindings." (interactive) (insert "WITH ") (insert (read-string "With bindings: ")) (insert " DO") (m3-newline) (m3-newline) (insert "END; (* with *)") (end-of-line 0) (m3-tab)) (defun m3-import () "Insert FROM ... IMPORT statement, prompting user for module." (interactive) (insert "FROM ") (insert (read-string "Import from module: ")) (insert " IMPORT ")) ; ; COMMANDS ; (defun m3-compile () "call m3c, argument is modulename derived from current buffer name." (interactive) (if (m3-is-oli) (compile (concat "m3c -g " (if (m3-is-def) "-i " "-m ") (m3-strip-extension (buffer-name)))) ; else (compile (concat "m3 -c -g " (m3-strip-bufnum (buffer-name))))) ) (defun m3-is-oli () (or (string-equal (m3-get-extension (buffer-name)) ".i") (string-equal (m3-get-extension (buffer-name)) ".m"))) (defun m3-position-of-end-of-line () "Returns position of end of line" (save-excursion (end-of-line) (point))) (defun m3-match-regexp-here (regexp) "Tries to match regexp at current position and before end of line" (let ((save-point (point))) (if (and (re-search-forward regexp (m3-position-of-end-of-line) t) (= (match-beginning 0) save-point)) t (goto-char save-point) nil))) (defun m3-multi-to-single-line-proc-header () "Convert multi line proc header to single line; do not call this directly" (backward-char) (let ((start-of-signature (point))) (forward-list) (re-search-forward "[=;]") (save-restriction (narrow-to-region start-of-signature (point)) (goto-char (point-min)) (save-excursion (replace-regexp "[ \t\n]+" " ")) (save-excursion (replace-string "( " "(")) (save-excursion (replace-string ") :" "):"))))) (defun m3-single-to-multi-line-proc-header () "Convert multi line proc header to single line; do not call this directly" (backward-char) (let ((start-of-signature (point))) (forward-list) (re-search-forward "[=;]") (save-restriction (narrow-to-region start-of-signature (point)) (goto-char (point-min)) (save-excursion (replace-string " RAISES" "\n RAISES")) (save-excursion (replace-regexp "\\([^*]\\)) ?:" "\\1)\n :")) (save-excursion (replace-string "; " ";\n ")) (forward-char) (insert "\n ")))) (defun m3-convert-proc-header () "Convert single line <-> multi line proc header" (interactive) (beginning-of-line) (let ((old-cfs case-fold-search)) (setq case-fold-search nil) (save-excursion (if (not (m3-match-regexp-here "\\(INLINE \\|\\) *PROCEDURE *[A-Za-z0-9_] + *(")) (message "Must be on first line of procedure header") (while (or (= (following-char) ? ) (= (following-char) ?\t)) (delete-char 1)) (if (or (= (following-char) ?\n) (= (following-char) ?\r)) (m3-multi-to-single-line-proc-header) (m3-single-to-multi-line-proc-header)))) (setq case-fold-search old-cfs))) (defun m3-search-path-line (name) "Appends given name to current line and sees if result is a file name. Returns either nil or the file name." (let ((old-point (point))) (if (not (search-forward "\n" nil t)) nil ; else (let* ((dir-name (m3-filename-expand (buffer-substring old-point (- (point) 1)))) (try (if (string= dir-name "") name (concat dir-name "/" name)))) (if (file-exists-p try) try (m3-search-path-line name)))))) (defun m3-filename-expand (name) (let ((pos 0) (spos 0) (epos 0) (res nil) ) (while (string-match "\\$(" name pos) (setq spos (match-beginning 0)) (setq res (concat res (substring name pos spos))) (setq epos (string-match ")" name spos)) (setq res (concat res (getenv (substring name (+ 2 spos) epos)))) (setq pos (1+ epos)) ) (setq res (concat res (substring name pos))) ) ) (defun m3-strip-extension (name) "Strips .ext from the given string (where ext is any extension)" (let ((dot-pos (string-match "\\." name))) (if dot-pos (substring name 0 dot-pos) name))) (defun m3-strip-bufnum (name) "Strips any from the given string" (let ((dot-pos (string-match "<" name))) (if dot-pos (substring name dot-pos nil) name))) (defun m3-get-extension (name) "Gets .ext from the given string (where ext is any extension)" (let ((dot-pos (string-match "\\." name))) (if dot-pos (let ((ext (substring name dot-pos nil)) ext_pos) (setq ext-pos (string-match "<" ext)) (if ext-pos (substring ext 0 ext-pos) ext)) ; else nil ) ) ) (defun m3-search-path (name path-file extension) "Uses path file to return full file name for given name and extension. Arguments are NAME - the file name to search for. PATHFILE - a string which is the name of a file containing newline separated directory names. The third argument is EXTENSION - a string. Takes NAME, extends it by EXTENSION then appends it to each directory given in PATHFILE until the name of an existing file is obtained. Then returns the full file name." (save-excursion (set-buffer (generate-new-buffer (concat "*" path-file "*"))) (delete-region (point-min) (point-max)) (let ((old-point-max (point-max)) (full-name (concat (m3-strip-extension name) "." extension))) (goto-char old-point-max) (if (file-readable-p path-file) (call-process "cat" path-file t)) (if (= (point-max) old-point-max) (if (file-exists-p name) full-name nil) ; else (goto-char old-point-max) (m3-search-path-line full-name))))) (defun m3-path-find-named-file (name path-file extension) "Uses path file to search and open file with given name and extension. Arguments are NAME - the file name to search for. PATHFILE - a string which is the name of a file containing newline separated directory names. The third argument is EXTENSION - a string. Takes NAME, extends it by EXTENSION then appends it to each directory given in PATHFILE until the name of an existing file is obtained. Then opens the file in the other window." (let ((file-name (m3-search-path name path-file extension))) (if file-name (find-file-other-window file-name)))) (defun m3-whole-prev-word () "Return word under or previous to point as a string" (buffer-substring (save-excursion (backward-word 1) (point)) (save-excursion (backward-word 1) (forward-word 1) (point)))) (defun m3-find-file-on-path (path-file extension) "Uses path file to search and open file named by current word and extension. Arguments are PATHFILE - a string which is the name of a file containing newline separated directory names. The second argument is EXTENSION - a string. Takes the word under point, extends it by EXTENSION then appends it to each directory given in PATHFILE until the name of an existing file is obtained. Then opens the file in the other window." (m3-path-find-named-file (m3-whole-prev-word) path-file extension)) (defun m3-path-find-file () "Visit interface corresponding to name currently under point. Looks down the m3path so it doesn't work unless all sources are on the m3path." (interactive) (if (m3-is-oli) (m3-find-file-on-path "m3path" "i") ; else (m3-find-file-on-path "m3path" "i3"))) ;(defun execute-monitor-command (command) ; (let* ((shell shell-file-name) ; (csh (equal (file-name-nondirectory shell) "csh"))) ; (call-process shell nil t t "-cf" (concat "exec " command)))) (defun m3-toggle-buffer () "Toggle between .i/.i3 and .m/.m3 files for the module." (interactive) (cond ((string-equal (m3-get-extension (buffer-name)) ".i") (find-file-other-window (concat (m3-strip-extension (buffer-name)) ".m"))) ((string-equal (m3-get-extension (buffer-name)) ".i3") (find-file-other-window (concat (m3-strip-extension (buffer-name)) ".m3"))) ((string-equal (m3-get-extension (buffer-name)) ".m") (find-file-other-window (concat (m3-strip-extension (buffer-name)) ".i"))) ((string-equal (m3-get-extension (buffer-name)) ".m3") (find-file-other-window (concat (m3-strip-extension (buffer-name)) ".i3"))))) ; ; PSEUDO ABBREV MODE ; (defvar m3-abbrev-enabled t "Boolean variable: is Modula 3 pseudo abbrev mode enabled?") (defun m3-toggle-abbrev () "Toggle the flag enabling/disabling Modula 3 pseudo abbrev mode." (interactive) (set 'm3-abbrev-enabled (not m3-abbrev-enabled))) (defun m3-prev-word () "returns last word in buffer." (buffer-substring (point) (save-excursion (backward-word 1) (point)))) (defun m3-is-abbrev (keyword word) "checks if word is abbreviation of given keyword." (if (> (length word) (length keyword)) () (string-equal (substring keyword 0 (length word)) (upcase word)))) (defun m3-if-abbrev-kill-prev (keyword word) "checks if word is abbreviation of keyword; if so deletes last word in buffer ." (if (not (m3-is-abbrev keyword word)) () (kill-word -1) t)) (defun m3-abbrev () "call appropriate m3-function depending on value of last word in buffer." (let ((pw (m3-prev-word))) (if (m3-if-abbrev-kill-prev "ABS" pw) (insert "ABS") (if (m3-if-abbrev-kill-prev "ADDRESS" pw) (insert "ADDRESS") (if (m3-if-abbrev-kill-prev "ADR" pw) (insert "ADR") (if (m3-if-abbrev-kill-prev "ADRSIZE" pw) (insert "ADRSIZE") (if (m3-if-abbrev-kill-prev "AND" pw) (insert "AND ") (if (m3-if-abbrev-kill-prev "ARRAY" pw) (m3-array) (if (m3-if-abbrev-kill-prev "BEGIN" pw) (insert "BEGIN") (if (m3-if-abbrev-kill-prev "BITS" pw) (insert "BITS ") (if (m3-if-abbrev-kill-prev "BITSIZE" pw) (insert "BITSIZE") (if (m3-if-abbrev-kill-prev "BOOLEAN" pw) (insert "BOOLEAN") (if (m3-if-abbrev-kill-prev "BRANDED" pw) (insert "BRANDED") (if (m3-if-abbrev-kill-prev "BY" pw) (insert "BY") (if (m3-if-abbrev-kill-prev "BYTESIZE" pw) (insert "BYTESIZE") (if (m3-if-abbrev-kill-prev "CARDINAL" pw) (insert "CARDINAL") (if (m3-if-abbrev-kill-prev "CASE" pw) (m3-case) (if (m3-if-abbrev-kill-prev "CEILING" pw) (insert "CEILING") (if (m3-if-abbrev-kill-prev "CHAR" pw) (insert "CHAR") (if (m3-if-abbrev-kill-prev "CONST" pw) (m3-const) (if (m3-if-abbrev-kill-prev "DEC" pw) (insert "DEC") (if (m3-if-abbrev-kill-prev "DISPOSE" pw) (insert "DISPOSE") (if (m3-if-abbrev-kill-prev "DIV" pw) (insert "DIV ") (if (m3-if-abbrev-kill-prev "DO" pw) (insert "DO ") (if (m3-if-abbrev-kill-prev "ELSE" pw) (m3-else) (if (m3-if-abbrev-kill-prev "ELSIF" pw) (insert "ELSIF") (if (m3-if-abbrev-kill-prev "END" pw) (insert "END") (if (m3-if-abbrev-kill-prev "EVAL" pw) (insert "EVAL") (if (m3-if-abbrev-kill-prev "EXCEPT" pw) (insert "EXCEPT") (if (m3-if-abbrev-kill-prev "EXCEPTION" pw) (m3-exception) (if (m3-if-abbrev-kill-prev "EXIT" pw) (insert "EXIT") (if (m3-if-abbrev-kill-prev "EXPORTS" pw) (insert "EXPORTS ") (if (m3-if-abbrev-kill-prev "FALSE" pw) (insert "FALSE") (if (m3-if-abbrev-kill-prev "FINALLY" pw) (insert "FINALLY") (if (m3-if-abbrev-kill-prev "FIRST" pw) (insert "FIRST") (if (m3-if-abbrev-kill-prev "FLOAT" pw) (insert "FLOAT") (if (m3-if-abbrev-kill-prev "FLOOR" pw) (insert "FLOOR") (if (m3-if-abbrev-kill-prev "FOR" pw) (m3-for) (if (m3-if-abbrev-kill-prev "FROM" pw) (m3-import) (if (m3-if-abbrev-kill-prev "IF" pw) (m3-if) (if (m3-if-abbrev-kill-prev "IMPORT" pw) (insert "IMPORT ") (if (m3-if-abbrev-kill-prev "IN" pw) (insert "IN") (if (m3-if-abbrev-kill-prev "INC" pw) (insert "INC") (if (m3-if-abbrev-kill-prev "INLINE" pw) (insert "INLINE") (if (m3-if-abbrev-kill-prev "INTEGER" pw) (insert "INTEGER") (if (m3-if-abbrev-kill-prev "INTERFACE" pw) (m3-module ?i) (if (m3-if-abbrev-kill-prev "LAST" pw) (insert "LAST") (if (m3-if-abbrev-kill-prev "LOCK" pw) (m3-lock) (if (m3-if-abbrev-kill-prev "LONGFLOAT" pw) (insert "LONGFLOAT") (if (m3-if-abbrev-kill-prev "LONGREAL" pw) (insert "LONGREAL") (if (m3-if-abbrev-kill-prev "LOOP" pw) (m3-loop) (if (m3-if-abbrev-kill-prev "LOOPHOLE" pw) (insert "LOOPHOLE") (if (m3-if-abbrev-kill-prev "MAX" pw) (insert "MAX") (if (m3-if-abbrev-kill-prev "METHODS" pw) (insert "METHODS") (if (m3-if-abbrev-kill-prev "MIN" pw) (insert "MIN") (if (m3-if-abbrev-kill-prev "MOD" pw) (insert "MOD") (if (m3-if-abbrev-kill-prev "MODULE" pw) (m3-module ?m) (if (m3-if-abbrev-kill-prev "NARROW" pw) (insert "NARROW") (if (m3-if-abbrev-kill-prev "NEW" pw) (insert "NEW") (if (m3-if-abbrev-kill-prev "NIL" pw) (insert "NIL") (if (m3-if-abbrev-kill-prev "NULL" pw) (insert "NULL") (if (m3-if-abbrev-kill-prev "NUMBER" pw) (insert "NUMBER") (if (m3-if-abbrev-kill-prev "NOT" pw) (insert "NOT ") (if (m3-if-abbrev-kill-prev "OBJECT" pw) (m3-object) (if (m3-if-abbrev-kill-prev "OF" pw) (insert "OF") (if (m3-if-abbrev-kill-prev "OR" pw) (insert "OR ") (if (m3-if-abbrev-kill-prev "ORD" pw) (insert "ORD") (if (m3-if-abbrev-kill-prev "PROCEDURE" pw) (m3-procedure) (if (m3-if-abbrev-kill-prev "RAISE" pw) (insert "RAISE") (if (m3-if-abbrev-kill-prev "RAISES" pw) (insert "RAISES") (if (m3-if-abbrev-kill-prev "READONLY" pw) (insert "READONLY") (if (m3-if-abbrev-kill-prev "REAL" pw) (insert "REAL") (if (m3-if-abbrev-kill-prev "RECORD" pw) (m3-record) (if (m3-if-abbrev-kill-prev "REF" pw) (insert "REF ") (if (m3-if-abbrev-kill-prev "REFANY" pw) (insert "REFANY") (if (m3-if-abbrev-kill-prev "REPEAT" pw) (m3-until) (if (m3-if-abbrev-kill-prev "RETURN" pw) (insert "RETURN") (if (m3-if-abbrev-kill-prev "REVEAL" pw) (insert "REVEAL") (if (m3-if-abbrev-kill-prev "ROUND" pw) (insert "ROUND") (if (m3-if-abbrev-kill-prev "SET" pw) (insert "SET OF ") (if (m3-if-abbrev-kill-prev "SUBARRAY" pw) (insert "SUBARRAY") (if (m3-if-abbrev-kill-prev "THEN" pw) (insert "THEN") (if (m3-if-abbrev-kill-prev "TO" pw) (insert "TO") (if (m3-if-abbrev-kill-prev "TRUE" pw) (insert "TRUE") (if (m3-if-abbrev-kill-prev "TRUNC" pw) (insert "TRUNC") (if (m3-if-abbrev-kill-prev "TRY" pw) (m3-try) (if (m3-if-abbrev-kill-prev "TYPE" pw) (m3-type) (if (m3-if-abbrev-kill-prev "TYPECASE" pw) (m3-typecase) (if (m3-if-abbrev-kill-prev "TYPECODE" pw) (insert "TYPECODE") (if (m3-if-abbrev-kill-prev "UNSAFE" pw) (insert "UNSAFE") (if (m3-if-abbrev-kill-prev "UNTIL" pw) (insert "UNTIL") (if (m3-if-abbrev-kill-prev "UNTRACED" pw) (insert "UNTRACED") (if (m3-if-abbrev-kill-prev "VAL" pw) (insert "VAL") (if (m3-if-abbrev-kill-prev "VALUE" pw) (insert "VALUE") (if (m3-if-abbrev-kill-prev "VAR" pw) (m3-var) (if (m3-if-abbrev-kill-prev "WHILE" pw) (m3-while) (if (m3-if-abbrev-kill-prev "WITH" pw) (m3-with) (message (format "%s is not a recognised abbreviation of a Modula 3 keyword" pw)) (m3-tab) )))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) ))))))))))))))))))))))) (defun m3-is-letter (ch) "checks if argument is a letter." (and (>= (upcase ch) ?A) (<= (upcase ch) ?Z))) (defun m3-abbrev-or-tab () "if preceding char in buffer is letter, tries to expand abbrev else tabs." (interactive) (if (and m3-abbrev-enabled (m3-is-letter (preceding-char))) (m3-abbrev) (m3-tab))) ; Finally a function for those used to M2 style text literals. It checks for ; text literals containing single quotes and ensures that they are preceded by ; a backslash. ; BUG: If a text literal contains an embedded double quote it is ignored (defun m3-text-literal-check () "Ensures that single quotes in text literals are preceded by backslash" (interactive) (save-excursion (goto-char (point-min)) (while (re-search-forward "[^\\\\]\"\\([^\"]*\\)[^\\\\]" nil t) (save-excursion (save-restriction (narrow-to-region (match-beginning 1) (match-end 1)) (goto-char (point-min)) (replace-regexp "\\([^\\\\]\\)'" "\\1\\\\'")))))) ------------------------------------------------------------------------------ Date: 18 Jul 91 16:38:40 GMT From: hasan@ut-emx.uucp (David A. Hasan) Subject: Re: Modules/Objects when and why? In article <9107171850.AA10003@jumbo.pa.dec.com> swart (Garret Swart) writes: >As Eliot Moss noted, often one uses an interface and a new type, either >an object type or not, together, because generally along with defining >a type and its operations one wants to give convenient access to their >names. However, one can group several types in a single interface >or use an interface just to hold a revelation of additional information >about another type or set of types. The ability to encapsulate two (or more) related types in one module is a feature which IMHO is absolutely crucial in order to capture the essence of some problem domains. Consider the domain of linear algebra: Here we have two kinds of objects: vectors and matrices. (Of course, we have a third: scalars of which vectors and matrices are collections, but this is really a generic parameter of the linear algebra class.) A natural way to capture the abstraction of this domain is to construct a single module containing * the Vector type * the Matrix type * operations on objects of either *or both* types. It is important to be able to include operations on both types in the module so that they can be implemented efficiently. Single-type modules discourage this appealing way of capturing the essence of "linear algebra". It *can* be done in Ada with the irritating residual that the "subtyping" mechanism (so called "derived types") introduces *incompatible* types. Thus, the case of "linear algebra" demonstrates why one would want an inheritance mechanism (so I can build off of Vectors) *and* a module mechanism (so Vectors and Matrices and be encapsulated together). Does this seem right? Is there another way to decompose the problem domain in this case? For example, one might observe that vectors and matrices are special cases of the more general notion of "tensors" and build a single-type linear algebra class based on this type. But in this case, much of the built-in array machinery of the host language must be sacrificed and in essence all the index arithmetic must be coded in a very general way so as to allow objects with any number of subscripts to be represented in the one tensor type. -- | David A. Hasan | hasan@emx.utexas.edu ------------------------------------------------------------------------------ Date: 18 Jul 91 12:51:06 GMT From: moss@cs.umass.edu (Eliot Moss) Subject: Re: FIRST applied to REF ARRAY This sounds reasonable to me, and consistent with the rest of the language. It's hard to see how it would introduce the possibility of programmer errors, too. But I'm not on the design committee :-) .... -- J. Eliot B. Moss, Assistant Professor Department of Computer and Information Science Lederle Graduate Research Center University of Massachusetts Amherst, MA 01003 (413) 545-4206, 545-1249 (fax); Moss@cs.umass.edu ------------------------------------------------------------------------------ Date: 18 Jul 91 12:55:05 GMT From: moss@cs.umass.edu (Eliot Moss) Subject: Re: Modules/Objects when and why? In article <9107171850.AA10003@jumbo.pa.dec.com> swart (Garret Swart) writes: - Ada has packages for controlling naming and a type system but that type system has no good mechanism for subtyping. [It does have something called 'abstracted types' (is that right? I can't remember the name) that provides something like a subtype relationship but nobody has been able to explain to me how one uses it. (But then again, I haven't been very eager to learn!)] Actually, they're called "derived types", and about all they allow is a new distinct name for an old type, with the new name inheriting all the representation and operations of the old type automatically. You can't really extend the type in a meaningful way. My understanding is that the intended use is to get better checking on physical units and the like, e.g., to help you keep your meters and liters straight. Of course it is a very limited system if that is the goal ... -- J. Eliot B. Moss, Assistant Professor Department of Computer and Information Science Lederle Graduate Research Center University of Massachusetts Amherst, MA 01003 (413) 545-4206, 545-1249 (fax); Moss@cs.umass.edu ------------------------------------------------------------------------------ Date: 18 Jul 91 18:25:18 GMT From: ramsey@parc.xerox.com (Norman Ramsey) Subject: Re: A comment about the SRC m3 driver In article "Dick Orgass" writes: >> I have yet to find a debugger that >> respects the #line pragmas for purposes of naming compilation units >> (i.e. files). >I must admit that I'm rather surprised that this is the case. I've been >using Modula-3 with four different dbx implementations (AIX 3.1, AOS 4.3 >and 2 for AIX PS/2) and all of them work as expected for Modula-3 source >file names, *.[im]3, when used with the SRC system (including naming >compilation units). Most debuggers work fine for naming source lines, but not for naming scopes (i.e. C compilation units), and therefore not for naming variables. Here's an example from the Sparc dbx, which shows that source line numbers are mapped correctly, but the full name of an argument or local variable is hopeless: (dbx) where _CDB__Execute(_command = 0x146e24 "", _input = 0x1c4028 "", _wr = 0x144224 ""), line 240 in "/net/palain/rosa/ramsey/ldb/src/sparcbin/./CDB.nw" ... (dbx) which _command `5540987543bb106_m`_CDB__Execute`_command I would prefer `CDB_m`_CDB__Execute`_command for obvious reasons. The MIPS dbx has trouble with line numbers of library routines, although this problem might be solved by the #line "CDB.m3" that Eric proposed. -- Norman Ramsey nr@princeton.edu [temporarily ramsey@parc.xerox.com, but mail to princeton] ------------------------------------------------------------------------------ Date: 18 Jul 91 19:05:25 GMT From: ramsey@parc.xerox.com (Norman Ramsey) Subject: Smarter recompilation of m3 programs I am the author of a moderately-sized m3 program (around 50 modules), and I'm finding make inadequate to my needs. I can use David Goldberg's tools to walk source code and build a dependency dag (by reading IMPORT statements), but using these dependencies in a makefile is unacceptable because an extension of an important interface can trigger massive recompilation (and a trip to lunch). The intermodule checker has two problems that I have discovered. The first is that it only works on one object file at a time, so if A --> B --> C in the dependency dag, and A changes, the imc can detect that B is out of date, but it can't detect a problem with C until B has been recompiled. If I don't know the dependency dag, I have to use the following algorithm to rebuild: attempt to link the program (e.g. type 'make') WHILE i don't have a linked program DO run the imc on all object files, invalidating bad ones attempt to link the program END the imc is slow, and linking is extremely slow, which makes this algorithm a real hassle, so I usually resort to: touch *.[mi]3 make & go to lunch Now, suppose I knew the dependency dag (courtesy Goldberg). Then I could be a little smarter by running the imc on the object files bottom-up, stopping to recompile every time I found a bad object file. This is appealing, except that the cost of starting a new imc for every object file is not negligble (measured in my time spent sitting and waiting). Since I would have to write a program to follow the dag anyway, I'm thinking of writing a variant of the imc that would run *once*, keeping its data structures in memory and updating them after recompilation. I'd like other m3 users to comment on this proposal. Are there others who have had trouble using make? Other clients for this tool? I'd also like comments from the SRC implementors. Will 2.0 still have version stamps? Will there be some other way to write such a tool? -- Norman Ramsey nr@princeton.edu [temporarily ramsey@parc.xerox.com, but mail to princeton] ------------------------------------------------------------------------------ Date: 19 Jul 91 07:31:21 GMT From: collberg@dna.lth.se (Christian S. Collberg) Subject: Modula-3 examples, anyone? Hi! I am in the process of learning Modula-3, but the lack of published educational material is making it difficult. If anyone has access to small but complete M3 programs that might aid beginners in understanding M3 concepts, I (and I am sure others) would appreciate it if they could post them to this newsgroup. Thanks! Christian -------------------------------------------------------------------- Christian.Collberg@dna.lth.se Department of Computer Science, Lund University, BOX 118, S-221 00 LUND, Sweden -- -------------------------------------------------------------------- Christian.Collberg@dna.lth.se Department of Computer Science, Lund University, BOX 118, S-221 00 LUND, Sweden ------------------------------------------------------------------------------ Date: Fri, 19 Jul 91 09:50:55 PDT From: Subject: Re: Smarter recompilation of m3 programs The 2.0 driver will do just what you want. If you say "m3 -make *.i3 *.m3", it will make a single bottom-up pass and compile only the units that import stale version stamps or whose source is newer than its object. Eric Muller built a working prototype of a similar driver that works with the 1.6 compiler. - Bill Kalsow ------------------------------------------------------------------------------ Date: 19 Jul 91 15:30:43 GMT From: preston@ariel.rice.edu (Preston Briggs) Subject: Re: Smarter recompilation of m3 programs How about an approach like those suggested by Tichy or Schwanke and Kaiser? Smart Recompilation Tichy TOPLAS, July 1986 Smarter Recompilation Schwanke and Kaiser TOPLAS, October 1988 I'm not certain of the applicability to Modula 3, but they both sound better than the current situation. Preston Briggs ------------------------------------------------------------------------------ Date: 19 Jul 91 20:38:00 GMT From: stt@inmet.inmet.com Subject: Re: Modules/Objects when and why? Re: Modules vs. Objects > /* ---------- "Modules/Objects when and why?" ---------- */ > A co-worker asked me a question about Modula-3 yesterday that, as a > Modula-3 new comer, I found myself unable to answer to either of our > satisfaction. He observed that Ada and C++ both have a single > abstraction mechanism, packages and classes respectively, whereas > Modula-3 appears to have two: modules and objects. Then he asked the > obvious question: "so when do I use modules and when do I use objects?" > I fumbled with it for a few minutes before confessing that "gee, I don't > really know." > > It seems to me that there is a difference in granularity, i.e. I think > of a module as being a "larger" thing than an object; on the other hand > objects provide a subtyping mechanism necessary for creating frameworks > and doing other useful object-oriented kinds of things. Neither of these > observations of the obvious provide any compelling guidelines for using > one versus the other though. Could someone enlighten us? Ada also has two aggregation mechanisms -- packages and records. The big difference is that packages are a compile-time thing, while records are more of a run-time thing. Packages (which are functionally identical to Modules) are used for organizing entities into a name space, and for partitioning the name space to enforce modularity and information hiding. Records are used to bundle components at run-time. New instances of records are creatable at run-time. There are arrays of records, linked lists of records, records passed as parameters, records returned from functions, etc. Generic packages can be defined, parameterized by types, and instantiated at compile-time. Discriminated types can be defined, parameterized by values, and "instantiated" at run-time. If you read Booch's excellent book on Object Oriented Design, he makes a clear distinction between modules and types/classes. In short -- modules are for organizing a program, types are for representing data. There is a bit of a religious battle in the language design world whether modules and types should be one and the same. In SmallTalk, Eiffel, etc., classes act both as modules and types. In C++, classes can act both as modules and types, though "files" are often used as a higher level "module" for organization purposes. In Ada, packages are the module, and types are types. > ... WkH > > Ward K Harold (512) 823-4139 [T/L 793-4139] > IBM Personal Systems Programming external: wkh@dce.austin.ibm.com > 11400 Burnet Rd., Zip 2603 internal: wkh@duke.austin.ibm.com > Austin, TX 78758 vnet: wharrold --ausvmq S. Tucker Taft stt@inmet.inmet.com Intermetrics, Inc. Cambridge, MA 02138 ------------------------------------------------------------------------------ Date: Sun, 21 Jul 91 17:53:23 GMT From: brian@babbage.csus.edu (Brian Witt) Subject: Re: Smarter recompilation of m3 programs In article <1991Jul18.190525.16256@parc.xerox.com> ramsey@parc.xerox.com (Norma n Ramsey) writes: >I am the author of a moderately-sized m3 program (around 50 modules), >and I'm finding make inadequate to my needs. I can use David >Goldberg's tools to walk source code and build a dependency dag (by >reading IMPORT statements), but using these dependencies in a makefile >is unacceptable because an extension of an important interface can >[description of modules A --> B --> C, and problems with this] > Since I would have to write a program to follow the dag >anyway, I'm thinking of writing a variant of the imc that would run >*once*, keeping its data structures in memory and updating them after >recompilation. How about running a program called, maybe 'bgmake', that is run once as a background task for each user. Upon startup it would examine some config file, generate a DAG and the needed building instructions, and then maybe output a message if anything was out of date. UNIX should be able to support this; I'm not too familar with VAX/VMS. Heck, on a VAX you might be able to have a 'make' detached server(?) ! Now, whenever the user wanted to test the program, she would run 'fgmake' which would send a signal (or IPC, whatever) to 'bgmake' that it is time to apply rules to the source and object files. The DAG's file would be checked to ensure the DAG is up to date. Of course, 'fgmake' would send over the file descriptors for its stdout and stderr sothat redirecting its output would _really_ redirect the output of the 'bgmake' make session. Alternatively, 'bgmake' could wake up once a minute and "sniff" files for date changes. If any occcur, the DAG would be recomputed in the background. The 'fgmake' program would be small and quick; just passing its args and some file descriptors to 'bgmake'. An X or SunViews port would be straight forward since 'fgmake' does so little. Maybe even TCL??? The 'bgmake' program would be no bigger than Xterm. :-) :-) :-) >I'd like other m3 users to comment on this proposal. Are there others >who have had trouble using make? Other clients for this tool? > >Norman Ramsey >nr@princeton.edu [temporarily ramsey@parc.xerox.com, but mail to princeton ] For alternate 'make' programs, you might want to check these out: 1) pmake -- Parallel make, part of the BSD Reno distribution. Source can be found at uunet(?). 2) dmake -- From Waterloo (in Canada). Has extensions to deal with subdirectories for just object files. Runs under UNIX and MS-DOS. 3) build -- Posted to comp.sources.unix. Remembers the flags used to generate a file in addition to the file dependencies. Also has multi-lingual support. From a group in Germany. -- ---------------------------------------------------------------- brian witt | brian@babbage.ecs.csus.edu You are what you click | (and if you click it twice...) Not representing Cal State Sacramento, the ECS dept, or Iraq ------------------------------------------------------------------------------ Date: 21 Jul 91 19:02:03 GMT From: harbison@bert.pinecreek.com (Sam Harbison) Subject: Re: Smarter recompilation of m3 programs Yes, I think a smarter tool for m3 programs is in order. Here's another case in which the Ada compiler people have done a lot of work that is relevant. I would be sure I was up to speed on Ada tools before designing a Modula-3 tool; otherwise you risk underachieving. Since I spent several years in the Ada compiler industry I would be willing to work offline with a group to come up with a requirements list and spec for such a tool. A really good tool could attract programmers to Modula-3. Here's some background... Ada and Modula-3 have similar module structures and problems. Most "big" Ada compilers--that is, those for DoD project use, not just low-price educational compilers--have "program librarians" that manage the compilation and recompilation of large programs, or even sets of programs, in a multi-user, multi-computer environment. Because Ada compilers are slow, these tools have gotten rather smart. They all use special databases that hold the (most recent) module dependency graphs and most are capable of: - computing "minimal" recompilations - automatically invoking the compiler on the right modules - updating the DAG as necessary when imports change - mapping module names to file names, removing the need to have a convention for file naming - managing "libraries" of precompiled code - managing "subprojects" in which some of the program's modules are different - insuring consistency in the presence of multiple simultaneous users These librarians are often the front-ends to the Ada system. Compilers and linkers are invoked by the librarian. Many librarian features require compiler support, but I think you will need such support eventually in any case. For instance, no Ada compiler would be competitive in the DoD market if it were not possible to have inline procedures declared in an interface with their bodies hidden in a module. When compiling a call to such a procedure, the compiler must fetch the proper body to expand it inline. This also puts a hidden compilation dependency between a client and the *module* containing the inline body. There are other subtleties... If you were designing a Modula-3 librarian today, you'd also want a graphical interface for X (e.g., Motif). If you really want to get fancy, something I have seen in the literature but not in practice is the ability to compute minimal compilations at the level of individual declarations. Concept: most modules use only a few declarations out of an interface. If that interface is changed and recompiled, but the used declarations have not changed, you don't have to recompile the module. This can save 40-80% of compilations, if I remember it right. Well, you might not want to go for the whole ball of wax at once, but you should know the competition. Sam Harbison Pine Creek Software; 305 S. Craig St., Suite 300; Pittsburgh, PA 15213 +1 412 681 9811; harbison@bert.pinecreek.com ------------------------------------------------------------------------------ Date: 22 Jul 91 14:34:06 GMT From: little_c@cho006.cho.ge.com (Chris Little) Subject: SURVEY of CS depts. (languages) I am a graduate student in Software Engineering interested in determining what the most popular computer languages used in UNDERGRADUATE computing sciences programs are, and why. I am curious to know the objectives and approaches of various CS departments in the contexts of languages and operating systems. Fro m your responses I will compile a summary and post it back to the USENET. There are only three questions which you can answer in as much detail as you feel is necessary. (1) What are your department's 3 most emphasized languages (and why)? (2) What are your department's 2 most emphasized operating systems (and why)? (3) How important do think your choice of languages and/or operating systems is to your overall CS program(s)? (i.e. as opposed to the other aspects of CS, in particular theory.) If you have any other information you might like to add, please do so. Your input is greatly appreciated. Direct e-mail responses please to little_c@cho006.cho.ge.com (Summer job) OR cml8@jaguar.uofs.edu or cml8@scranton.bitnet (University of Scranton, PA) Thank you. -- Chris Little GE Fanuc Automation, Charlottesville, Virginia (804) 978-627 4 little_c@cho006.cho.ge.com cml8@scranton.bitnet cml8@jaguar.uofs.ed u ------------------------------------------------------------------------------ Date: Mon, 22 Jul 91 13:50:50 PDT From: mjordan@src.dec.com (Mick Jordan) Subject: Re: Smarter recompilation of m3 programs In article <1991Jul21.175323.23224@csusac.csus.edu>, brian@babbage.csus.edu (Br ian Witt) writes: > How about running a program called, maybe 'bgmake', that is run once as > a background task for each user. Upon startup it would examine some config > file, generate a DAG and the needed building instructions, and then maybe > output a message if anything was out of date. UNIX should be able to > support this; I'm not too familar with VAX/VMS. Heck, on a VAX you might be > able to have a 'make' detached server(?) ! > > ... >Alternatively, 'bgmake' could wake up once a minute and "sniff" files for >date changes. If any occcur, the DAG would be recomputed in the background. >The 'fgmake' program would be small and quick; just passing its args >and some file descriptors to 'bgmake'. An X or SunViews port would be >straight forward since 'fgmake' does so little. Maybe even TCL??? >The 'bgmake' program would be no bigger than Xterm. :-) :-) :-) Some of this is already available in the 'm3check' tool that is part of the Modula-3 toolkit 'm3tk', available from SRC by ftp from gatekeeper:/pub/DEC/Modula-3/m3tk/dist-1.0.tar.Z. It "sniffs" for file changes at the users request and then "compiles" the correct set of units (based on nai ve dependency analysis). The DAG is in fact just part of the data encoded in the ASTs of the units. The only "build" back-end that I have is via a Makefile, but its just a SMOP to construct alternatives. Unfortunately, because it builds on a compiler front-end, its a little larger than Xterm! I also have some code, not distributed with m3tk, which supports the client/ser ver model using socket streams. I am currently looking at a Tcl/Tk interface to m3 check. Mick Jordan ------------------------------------------------------------------------------ Date: 22 Jul 91 21:24:06 GMT From: ramsey@parc.xerox.com (Norman Ramsey) Subject: Re: Smarter recompilation of m3 programs In article <1991Jul21.175323.23224@csusac.csus.edu> brian@babbage.csus.edu (Bri an Witt) writes: >How about running a program called, maybe 'bgmake', that is run once as >a background task for each user. Upon startup it would examine some config >file, generate a DAG and the needed building instructions, and then maybe >output a message if anything was out of date. Why run in the background? If Pkl works correctly, such a program can easily save its state on disk for quick recovery. -- Norman Ramsey nr@princeton.edu [temporarily ramsey@parc.xerox.com, but mail to princeton] ------------------------------------------------------------------------------ Date: 23 Jul 91 12:17:11 GMT From: buschman@tubsibr.uucp (Andreas Buschmann) Subject: default values of all sorts of pointers (references, procedures) Hi! According to the Modula3 Report an Object's methods are initialized to NIL if nothing else is declared. Does the same hold for other procedure variables and ordinary references? Or do I mix things up with CLU? The problem is with a sentence about variable declaration on page 29 of the report: ``If E (the default value of a variable) is omitted, the initial value is an arbitrary value of type T.'' Am I guaranteed a value in the range of T, or an arbitrary array of bits of the size of T? Tschuess Andreas ------------------------------------------------------------------------------ Date: Tue, 23 Jul 91 13:25:57 PDT From: muller@src.dec.com (Eric Muller) Subject: Re: default values of all sorts of pointers (references, procedures) In article <1991Jul23.121711.25429@ibr.cs.tu-bs.de>, buschman@tubsibr.uucp (And reas Buschmann) writes: > According to the Modula3 Report an Object's methods are initialized to > NIL if nothing else is declared. > Does the same hold for other procedure variables and ordinary > references? Or do I mix things up with CLU? No, you just have the guarantee of the sentence: > ``If E (the default value of a variable) is omitted, the initial value > is an arbitrary value of type T.'' If you have: VAR v : [5..6]; you are guaranteed that the initial value of v will be 5 or 6. If you have: VAR v, w: PROCEDURE (); you are guaranteed that v will be NIL or be a reference to a procedure whose signature covers PROCEDURE (). There is no guarantee that w will have the same value, nor that that value for v will be the same for all executions. If your code relies on the initial value NIL, just says so in the variable declaration. --- Eric. ------------------------------------------------------------------------------ Date: 23 Jul 91 23:26:12 GMT From: lins@Apple.COM (Chuck Lins ) Subject: Re: default values of all sorts of pointers (references, procedures) In article <1991Jul23.121711.25429@ibr.cs.tu-bs.de> buschman@tubsibr.uucp (Andr eas Buschmann) writes: >According to the Modula3 Report an Object's methods are initialized to >NIL if nothing else is declared. >Does the same hold for other procedure variables and ordinary >references? Or do I mix things up with CLU? > >The problem is with a sentence about variable declaration on page 29 >of the report: >``If E (the default value of a variable) is omitted, the initial value >is an arbitrary value of type T.'' >Am I guaranteed a value in the range of T, or an arbitrary array of bits of >the size of T? > The statement reads to me that the initial value must conform to the type T, but it could be anything. I susprect that the latter is more likely however. Personally, I think that zeroing out a variable is a useful default initial value. Covers plently of common cases. Just a personal suggestion to the m3 folks that this should be done in the interest of safety and simplicity. Slightly off the subject, I presume everyone is going to Loughborough? Chuck Lins "The easy-to-use Computer Company". -- Chuck Lins | "Shut up! Be happy!" -- Jello Biafra Apple Computer, Inc. | Looking for RISC Oberon compiler job. 20525 Mariani Avenue | Resume available on request. Mail Stop 58-C | Internet: lins@apple.com Cupertino, CA 95014 | ------------------------------------------------------------------------------ Date: Mon, 29 Jul 91 16:50:57 PDT From: muller@src.dec.com (Eric Muller) Subject: filename length summary Thanks to those who answered my querry about the length of filenames. Here is a scheme which seems to satisfy most systems: - filenames are limited to 11 characters + '.' + 2 characters of extension - the first 8 characters converted to uppercase must be unique - accesses from Modula-3 programs will be via an interface that will convert names in a system-dependent way; for example, a DOS version may retain only the first 8 character of the given name. -- Eric. ------------------------------------------------------------------------------ Date: Mon, 29 Jul 91 16:58:43 PDT From: muller@src.dec.com (Eric Muller) Subject: Re: filename length summary In article <1991Jul29.165057.29233@src.dec.com>, I wrote: > - the first 8 characters converted to uppercase must be unique I was thinking of the characters before the '.'. VeryLongName1.i3 and VeryLongName2.i3 conflict, but VeryLongName1.i3 and VeryLongName1.m3 don't. Sorry for the possible confusion, Eric. ------------------------------------------------------------------------------ Date: 30 Jul 91 04:41:53 GMT From: shite@sinkhole.unf.edu (Stephen Hite) Subject: Is anyone porting Modula-3 to SVR4? Does anyone here foresee any major problems in porting SRC Modula-3 to System V Release 4 on the 386 PC's ? Long filenames, symbolic links, much of the Berkeley world...sounds like it could be fairly painless. Steve Hite shite@sinkhole.unf.edu ------------------------------------------------------------------------------