======================================================================= 1 ===
Date:    02 Jan 1995 09:50:26 GMT
From:    jojo@strawinsky.informatik.rwth-aachen.de (Joachim Bausch)
Subject: pickle

Dear Modula-3 users:

I have encountered a problem with Pickle.

I would like to write a graph-structure to disk using 
a simple call to Pickle.Write. I have taken the
required precautions such as explicit branding and no
procedure variables.

The program will crash while trying to execute
that call with the following message:

	sendsig: bad signal stack pid=17614, sig=11
	sigsp = 0x2aa8c8, action = 0xef020ba0, upc = 0xef6ba544
	[2]  + illegal instruction  adt

Running the program in gdb will yield the message:

	Program received signal SIGSEGV, Segmentation fault.
	16_ef6af6cc in ThreadPosix.XRelease (m=???) at ThreadPosix.m3:438
	ThreadPosix.m3:438: No such file or directory.	

So I suppose that the program crashes somewhere in a run-time
library. Does anuone have any idea what I could do about
the problem? Is there any obvious mistake I could have made?
I need to use NetObjects and I understand that
they use Pickle, too. So I cannot really work around that point.

My system's configuration is: 
m3-3.3 on a SPARCstation 10 with SUNOS 4.1.3

Thank you very much for your help,

-- 

email: jojo@i3.informatik.rwth-aachen.de
smail: Joachim Bausch, Lehrstuhl f. Informatik III
       Ahornstr. 55, 52074 Aachen, Germany
phone: +49/241/80-21320     fax:  +49/241/8888-218





======================================================================= 2 ===
Date:    Tue, 3 Jan 1995 00:09:02 GMT
From:    g@clio.demon.co.uk (Gareth Webber)
Subject: Linux LOCKs

Is there a problem with the LOCKs set up under Linux M3 version 3.3 as I
have a program which behaves perfectly (apart from concurrency problems...)
without locks but as soon as I protect data to remove the concurency issues
the program gives a deferencing NIL pointer exception. Is this a known
problem ? I am using the larger of Michael Dagenais's versions.

I have heard whispers of a version 3.4. Is there a likely release date ?
What new features are there ?

TIA, gary... 

-- 
Gareth Webber,                                          g@clio.demon.co.uk
Trinity Hall,						gpw1000@cus.cam.ac.uk
Cambridge.      					gary@royle.org

                        "Ne te confudant illegitimi"


======================================================================= 3 ===
Date:    Tue, 3 Jan 1995 17:53:36 GMT
From:    shang@corp.mot.com (David L. Shang)
Subject: Re: Cows, Hogs & Farms

In article <1994Dec29.013815@hobbit>  writes:
> Note:  This post was originally on comp.lang.eiffel
> 
> > In article <milodD12zJ9.GD3@netcom.com>
> > milod@netcom.com (John DiCamillo) writes:
> 
> >> chrisb@stork.cssc-syd.tansu.com.au (Chris Bitmead) writes:
> 
> >>> In article <milodD0Equ1.3Fr@netcom.com>
> >>> milod@netcom.com (John DiCamillo) writes:
> 
> >>> How does covarience *really* work in Eiffel?
> >>>
> >>> class COW
> >>> inherit
> >>>     HERBIVORE redefine eat
> >>> feature eat(food: GRASS) is ...
> >>>
> >>> class HOG
> >>> inherit
> >>>     HERBIVORE redefine eat
> >>> feature eat(food: CORN) is ...
> >>>
> >>> class FARM
> >>> feature
> >>>     LIST[HERBIVORE] livestock; -- cows and hogs
> >>>     LIST[PLANT]     foodstuff; -- grass and corn
> >>>...
> >>>     livestock.value.eat(foodstuff.value);
> >>>
> >>> Is there a compile-time or a run-time error?  What
> >>> happens?
> 
> 
> I'm cross-posting this to comp.object, comp.lang.eiffel & comp.lang.sather
> to get some discussion from people who are trying to do these complex
> things as well as for those of us who are still just talking about it.
> 
> Here's how it might be done:

> ...
> class herbivore is
>   inherit plants.plant;
>   procedure eat ( food is in plant );
> end herbivore;
> 
> class herbivore body is
>   variable data is plant;
>   procedure eat ( get data is  out plant;  -- "get" binds data to the proc.
>                       food is in   plant ) is
>   begin
>     data := food;            -- food the herbivore has most recently eaten
>   end eat;
> end herbivore;
> ...

To make the implementation interface diferent from the exported interface is  
not a good idea to handle this situation.

By your herbivore class, you declare that a herbivore can eat any plant.  
Therefore, if hog and cow are herbivores, they should eat any plant, otherwise 
 
they are not herbivores. If hog and cows are herbivores in the real world,  
then, your definition of herbivore class is wrong. It makes a false promise on 
 
which its subclasses cannot agree.

It really depends on the precision that you want to model the real world. If  
you do not care the futher classification of herbivores on their food types  
(plants), the definition of "procedure eat ( food is in plant )" is fine for a 
 
herbivore class.

But if you do care the classification of herbivores on their food types,  
herbivore should be an abstract class because its real food type is unknown  
yet. The way it eats may be unknown either. Therefore, a herbivore class should
  
be:

class herbivore [FoodType <: plant] is
   procedure eat ( food is in FoodType );
end herbivore;

Then, you can have cows and hogs:

class hog is herbivore [FoodType = corn];
class cow is herbivore [FoodType = grass];

If farms are a collection of herbivores with a field where their food grows, we
  
should think about how to model a farm. There are three different ways.

Firstly, you could have a homogeneous farm where only on type of herbivores are
  
raised:

class field [FoodType <: plant]
   function getCrop(): FoodType;
end field;

class farm [AnimalType <: herbivore] is
  animals: list [MemberType = AnimalType];
  fields:  list [MemberType = field [FoodType = AnimalType.FoodType]];
  function getRipeFood(): AnimalType.FoodType;
	   -- get the ripe food from one of its fields.
  ...
end farm;

class hog_farm is herbivore [AnimalType = hog];
class cow_farm is herbivore [AnimalType = cow];

You do not need any run-time type check or system validation for this kind of  
farm within a close world:

program farming is
         c is cow_farm;
         h is hog_farm;
begin
  ...
  for each animal in c.animals do animal.eat(aCorn); -- wrong!
  for each animal in c.animals do animal.eat(aGrass); -- correct.
  for each animal in c.animals do animal.eat (c.getRipeFood ()); -- correct.
end farming.

You do not need any run-time type check or system validation for this kind of  
farm even with an open world if the type dependency is known statically:

procedure farming 
	  [FarmType <:farm] 
	  (f: FarmType; food: FarmType.AnimalType.FoodType)
begin
  ...
  for each animal in f.animals do animal.eat(food); -- correct
end farming.

procedure self_farming (f: farm)
begin
  ...
  for each animal in f.animals do animal.eat(f. getRipeFood()); -- correct
end self_farming.

Secondly, you could have an ill-structured heterogeneous farm where various  
type of herbivores are raised at random fields. That is, there is no  
relationship between a field type and a herbivore type:

class farm is
  animals: list [MemberType <: herbivore];
  fields:  list [MemberType <: field];
  function getRipeFood(): plant;
	   -- get the ripe food from one of its fields.
end farm;

You need run-time type check or system validation for this ill-structured farm:

procedure self_farming is (f is in farm)
begin
  ...
  for each animal in f.animals do animal.eat(f.getRipeFood ()); -- wrong!
  for each animal in f.animals do 
	plant food := f.getRipeFood();
	when typeof(animal).Foodtype = typeof(food) do
	     animal.eat(food); -- correct
  end
end self_farming.

Lastly, you could have an well-structured heterogeneous farm where each type of
  
herbivores are raised at the field that grows their own food. That is, there is
  
a relationship between a field type and a herbivore type:

class group [AnimalType <: herbivore] is
  animals: list [MemberType = AnimalType];
  fields:  list [MemberType = field [FoodType = AnimalType.FoodType]];
  function getRipeFood(): AnimalType.FoodType;
	   -- get the ripe food from one of its fields.
  ...
end group;

class farm is
  groups: group;
  ...
end farm;

When you do self farming, you do not need run-time type check or system  
validation for this well-structured farm:

procedure self_farming is (f is in farm)
begin
  ...
  for each group in f.groups do
      for each animal in group do
          animal.eat(group.getRipeFood ()); -- correct!
end self_farming.

I really cannot tell you which way is the best. It depends on the requirement  
of your problem domain. However, a good language should provide all the  
possible ways.

The language BETA and Cluster come close to what I presented above.

David Shang





======================================================================= 4 ===
Date:    3 Jan 1995 13:43:14 -0500
From:    russo@cs.purdue.edu (Vincent F. Russo)
Subject: Call For Papers: COOTS '95




	         Announcement and Call for Papers
                                             
            Conference on Object-Oriented Technologies
                              (COOTS)
                                             
                          June 26-29, 1995
                       Monterey, California, USA
                                             
                Sponsored by the USENIX Association

IMPORTANT DATES
Submissions due:                         March 6, 1995
Notification to authors:                 April 3, 1995
Camera-ready final papers due:           May 15, 1995

PRELIMINARY PROGRAM COMMITTEE
Program Chair:  Vincent F. Russo, Purdue University
Tutorial Program Chair:  Doug Lea, SUNY Oswego
Luca Cardelli, Digital Systems Research Center
Murthy Devarokonda, IBM Watson Research Labs
Ted Goldstein, SUN Microsystems Labs.
Paul Leach, Microsoft
Mark Linton, Silicon Graphics Inc.
Chris Pettus, Taligent
Jim Waldo, SUN Microsystems Labs.

OVERVIEW
The COOTS conference is designed to be the showplace for advanced development
work in object-oriented technologies.  The conference will emphasize research
and experience derived from efforts to use object-oriented techniques to build
complex systems that meet real world needs.

The COOTS conference will begin with two days of tutorials.  The tutorial
program will offer a selection of tutorials from among several tracks.  We
expect tutorial topics to include:
   * distributed object systems (CORBA, etc.)
   * object-oriented network programming
   * alternative object-oriented languages
   * advanced techniques in memory management
   * efficient and effective class design

Two days of technical sessions will follow the tutorials.  Proceedings of the
conference will be published by USENIX and will be provided free to technical
session attendees; additional copies will be available for purchase from
USENIX.

Like the USENIX C++ Conferences and Advanced Topics Workshops from which it is
derived, COOTS will emphasize the advanced engineering aspects of object
technology.  While papers covering work in C++ are encouraged, the conference i
s
broader in scope than its ancestors and invites submissions describing results
and work in other object-oriented or object-based languages.

CONFERENCE TOPICS
We seek papers describing original work concerning the design, implementation,
and use of object-oriented technologies.  Questions regarding a topic's
relevance may be addressed to the program chair via electronic mail to
russo@cs.purdue.edu.

Potential topics include: 
   * work on object-oriented programming languages
      (C++, Modula-3, Eiffel, etc.)
   * implementations of commercial object infrastructures
      (CORBA, NextStep, OLE-II, SOM/DSOM, etc.)
   * interface description languages
   * distributed object systems
   * unique applications of and experiences with object-oriented
      technologies

WHAT TO SUBMIT
Submissions must be received by March 6, 1995.  Full papers should be 10 to 15
pages.  Instead of a full paper, authors may submit an extended abstract which
discusses key ideas.  Extended abstracts should be 5-7 pages long (about
2500-3500 words), not counting references and figures.  The body of the extende
d
abstract should be complete paragraphs.  The object of an extended abstract is
to convince the reviewers that a good paper and presentation will result.
While, by acceptance of extended abstracts, we intend to stimulate industrial
participation, submission of extended abstracts by academics is in no way
discouraged.

All submissions will be judged on originality, relevance, and correctness.  Eac
h
accepted submission will be assigned a member of the program committee to act a
s
its shepherd through the preparation of the final paper.  The assigned member
will act as a conduit for feedback from the committee to the authors.
Camera-ready final papers are due May 15, 1995.

Please accompany each submission by a cover letter stating the paper title and
authors along with the name of the person who will act as the contact to the
program committee.  Please include a surface mail address, daytime and evening
phone number, and, if available, an email address and fax number for the contac
t
person.

If you would like to receive detailed guidelines for submission and examples of
extended abstracts, you may telephone the USENIX Association office at +1 510
528-8649, or email to cootsauthors@usenix.org or to the program committee
chair.

The COOTS conference, like most conferences and journals, requires that papers
not be submitted simultaneously to another conference or publication and that
submitted papers not be previously or subsequently published elsewhere.  Papers
accompanied by "non-disclosure  agreement" forms are not acceptable and will be
returned to the author(s) unread.  All submissions are held in the highest
confidentiality prior to publication in the Proceedings, both as a matter of
policy and in accord with the U.S.  Copyright Act of 1976.

WHERE TO SUBMIT
Please send one copy of a full paper or an extended abstract to the program
committee via one of the following methods.  All submissions will be
acknowledged.

  o Preferred Method: email (Postscript or ASCII) to
             cootspapers@usenix.org

  o Alternate Method: postal delivery to
              USENIX COOTS Conference
              c/o Dr.  Vincent F.  Russo
              Department of Computer Sciences
              Purdue University
              West Lafayette, IN  47907
              U.S.A.  
              +1 317 494-6008

REGISTRATION MATERIALS
Materials containing all details of the technical and tutorial programs,
registration fees and forms, and hotel information will be available beginning
in April 1995.   If you wish to receive the registration materials, please
contact USENIX at:
                        USENIX Conference Office
                        22672 Lambert Street, Suite 613
                        Lake Forest, CA USA   92630
                        +1 714 588-8649; Fax: +1 714 588-9706
                        Internet: conference@usenix.org



======================================================================= 5 ===
Date:    Tue, 3 Jan 1995 15:56:04 GMT
From:    cs_wcm@ug.cs.ust.hk (Woo Chat Ming)
Subject: Is m3 suitable for me ?

I am working on a project to stimulate the performance of optical computer
network. I am deciding what language to use. I want the program to have
a graphic user interface ( i.e. the user should be able press the buttons
to change parameters, and the flowing of messages between nodes should be 
displayed graphically like a movie as the simulation goes on.) 

Is modula-3 suitable for this project ? I am new to modula-3 and I have never
programmed in neither windows and X-win envirnoment. I have never used Motif.
Is X-win programming in modula-3 difficult to learn ? Which books/material
is good for beginner like me ?

Thank you for any suggestion.

Woo Chat Ming.



======================================================================= 6 ===
Date:    Wed, 4 Jan 1995 01:03:07 GMT
From:    hgeorge@eskimo.com (Harry George)
Subject: Which OS for Modula-3

I have a 486-66 PC with 16Mbyte and a Mitsumi CD ROM.  I want to
do serious Modula-3 coding (not just try it out a few times).

What's your recommendation for an OS.  Assume I am busy until midsummer,
so something available then is ok.  Linux? (Slackware?) OS/2? WinNT?
FreeBSD?

Thanks,
-- 
Harry George
email: hgeorge@eskimo.com
smail: 22608 90th Ave W / Edmonds WA 98026
quote: "The reasonable man adapts himself to the world;
       the unreasonable one persists in trying to adapt
       the world to himself.  Therefore, progress depends 
       on the unreasonable man." G. B. Shaw



======================================================================= 7 ===
Date:    3 Jan 95 22:30:31 EDT
From:    hathawa2@marshall.edu (Mark S. Hathaway)
Subject: Re: Cows, Hogs & Farms

> In article <1995Jan3.175336.14940@schbbs.mot.com>,
> shang@corp.mot.com (David L. Shang) writes:

>> In article <1994Dec29.013815@hobbit>
>> hathawa2@marshall.edu (Mark S. Hathaway) writes:

>> Note:  This post was originally on comp.lang.eiffel
 
>>> In article <milodD12zJ9.GD3@netcom.com>
>>> milod@netcom.com (John DiCamillo) writes:
 
>>>> chrisb@stork.cssc-syd.tansu.com.au (Chris Bitmead) writes:
 
>>>>> In article <milodD0Equ1.3Fr@netcom.com>
>>>>> milod@netcom.com (John DiCamillo) writes:
 
>>>>> How does covarience *really* work in Eiffel?
>>>>>
>>>>> class COW
>>>>> inherit
>>>>>     HERBIVORE redefine eat
>>>>> feature eat(food: GRASS) is ...
>>>>>
>>>>> class HOG
>>>>> inherit
>>>>>     HERBIVORE redefine eat
>>>>> feature eat(food: CORN) is ...
>>>>>
>>>>> class FARM
>>>>> feature
>>>>>     LIST[HERBIVORE] livestock; -- cows and hogs
>>>>>     LIST[PLANT]     foodstuff; -- grass and corn
>>>>>...
>>>>>     livestock.value.eat(foodstuff.value);
>>>>
>>>>> Is there a compile-time or a run-time error?  What
>>>>> happens?
 
>> ...

It appears Mr. Shang has added comp.lang.beta and some other(s) to the
distribution list.  Perhaps it will expand the conversation to others who
can enlighten us all.
 
>> Here's how it might be done:
>> 
>> ...
>> class herbivore is
>>   inherit plants.plant;
>>   procedure eat ( food is in plant );
>> end herbivore;
>> 
>> class herbivore body is
>>   variable data is plant;
>>   procedure eat ( get data is  out plant;  -- "get" binds data to the proc.
>>                       food is in   plant ) is
>>   begin
>>     data := food;            -- food the herbivore has most recently eaten
>>   end eat;
>> end herbivore;
>> ...
 
> To make the implementation interface diferent from the exported interface is 
 
> not a good idea to handle this situation.

I'm not keen on the idea of a class body having global data, so the added
parameter binds the method to particular data within the class.  There could
be several variables which together define the object.  By binding only the
particular one(s) to a method it should be clearer what is acting on what.

Will you elaborate on your view?
 
> By your herbivore class, you declare that a herbivore can eat any plant.  
> Therefore, if hog and cow are herbivores, they should eat any plant,
> otherwise they are not herbivores. If hog and cows are herbivores in the
> real world, then, your definition of herbivore class is wrong. It makes
> a false promise on which its subclasses cannot agree.

If grass and corn are all they will eat then the way I wrote it is correct.
If they will eat other plants then the constraint that the hog and cow
should only eat grass and corn aren't defined in those classes then it would
have to be introduced later.  I wouldn't object to that.  We wouldn't want
them eating anything dangerous.  :-)

I was following the example of the original post to comp.lang.eiffel.

> It really depends on the precision that you want to model the real world. If 
 
> you do not care the futher classification of herbivores on their food types  
> (plants), the definition of "procedure eat ( food is in plant )" is fine
> for a herbivore class.
> 
> But if you do care the classification of herbivores on their food types,  
> herbivore should be an abstract class because its real food type is unknown  
> yet. The way it eats may be unknown either. Therefore, a herbivore class
> should be:
>
> class herbivore [FoodType <: plant] is
>    procedure eat ( food is in FoodType );
> end herbivore;

A herbivore's food is plant material.  I only gave the type plant as the
foods there might be on a farm.  If I was being more thorough I'd have
defined plant more completely and have made even more readers angry with
me for making the post too long.  Besides, it wasn't the point of the example.

In my example the "way it eats" is undefined.  All that is recorded is what
was eaten most recently.  I didn't even begin to discuss the chewing of cud.

Without defining "plant" you've left yourself open for problems.  Somehow
someone will have to get around to defining it for this to work.
 
> Then, you can have cows and hogs:
> 
> class hog is herbivore [FoodType = corn];
> class cow is herbivore [FoodType = grass];

Funny how you, too, specify corn & grass as the foods these animals can eat.
It's the most natural way to describe a HOG or COW.  If there are other
plants these animals eat then there should be a subset of "plants" created
for each of them.
 
> If farms are a collection of herbivores with a field where their food
> grows, we should think about how to model a farm. There are three
> different ways.

In the example from the comp.lang.eiffel post there were only HOG & COW and
an example FARM.  I tried not to stray too far from that.
 
> Firstly, you could have a homogeneous farm where only on type of herbivores
> are raised:
> 
> class field [FoodType <: plant]
>    function getCrop(): FoodType;
> end field;

Isn't a generic field which can grow any plant more correct?  Doesn't the
notation you've given tie one specific plant to the field and not allow for
future crop rotations?  Farmers plant different crops to avoid depleting the
soil too much.
 
> class farm [AnimalType <: herbivore] is
>   animals: list [MemberType = AnimalType];
>   fields:  list [MemberType = field [FoodType = AnimalType.FoodType]];
>   function getRipeFood(): AnimalType.FoodType;
> 	   -- get the ripe food from one of its fields.
>   ...
> end farm;
> 
> class hog_farm is herbivore [AnimalType = hog];
> class cow_farm is herbivore [AnimalType = cow];

Why would a farm be a herbivore?

I don't care for your syntax which appears to only allow single inheritance.
What if a COW is not only a HERBIVORE, but a DOMESTICATED_ANIMAL?  I could
write...

  class cow is
    inherit herbivore;
    inherit domesticated_animal;
  end cow;

Perhaps you're right that I should have developed a generic farm and then
populated it with particular animals.  That wouldn't be too difficult, as
you showed.  Again, I wasn't focusing on these peripheral classes as much
as on the COW and HOG classes and how to build the FARM from them.

All this shows how difficult it is to fully define something as simple as
a farm.  Once you begin to model the real world things get very complicated.
 
> You do not need any run-time type check or system validation for this
> kind of farm within a close world:
> 
> program farming is
>          c is cow_farm;
>          h is hog_farm;
> begin
>   ...
>   for each animal in c.animals do animal.eat(aCorn); -- wrong!
>   for each animal in c.animals do animal.eat(aGrass); -- correct.
>   for each animal in c.animals do animal.eat (c.getRipeFood ()); -- correct.
> end farming.

What if the farmer sells some cows and buys some hogs to have a mixed farm?
How do you readjust to handle this?
 
> You do not need any run-time type check or system validation for this kind
> of farm even with an open world if the type dependency is known statically:
> 
> procedure farming 
> 	  [FarmType <:farm] 
> 	  (f: FarmType; food: FarmType.AnimalType.FoodType)
> begin
>   ...
>   for each animal in f.animals do animal.eat(food); -- correct
> end farming.

Sure, it's easier if it's a homogeneous farm because you don't have to
figure-out what food to match with which animal and if it's grown in the
field where the animal is and if it's ripe.  The real world is complicated.

> procedure self_farming (f: farm)
> begin
>   ...
>   for each animal in f.animals do animal.eat(f. getRipeFood()); -- correct
> end self_farming.
> 
> Secondly, you could have an ill-structured heterogeneous farm where various  
> type of herbivores are raised at random fields. That is, there is no  
> relationship between a field type and a herbivore type:
> 
> class farm is
>   animals: list [MemberType <: herbivore];
>   fields:  list [MemberType <: field];
>   function getRipeFood(): plant;
> 	   -- get the ripe food from one of its fields.
> end farm;

Why do you say "animals: list [MemberType <: herbivore];"
instead of      animals: list [ herbivore ];
?

And, how does "herbivore" define a COW or HOG when they could easily be
created from both HERBIVORE and DOMESTICATED_ANIMAL?  What would you do
in that case?
 
> You need run-time type check or system validation for this ill-structured
> farm:
> 
> procedure self_farming is (f is in farm)
> begin
>   ...
>   for each animal in f.animals do animal.eat(f.getRipeFood ()); -- wrong!
>   for each animal in f.animals do 
> 	plant food := f.getRipeFood();
> 	when typeof(animal).Foodtype = typeof(food) do
> 	     animal.eat(food); -- correct
>   end
> end self_farming.

This version of farming() looks pretty good.  I like the use of "typeof()"
also.  It's quite useful.  My example was difficult to read compared to this.
 
> Lastly, you could have an well-structured heterogeneous farm where each
> type of herbivores are raised at the field that grows their own food. That
> is, there is a relationship between a field type and a herbivore type:

But, if an animal (or group of animals) is put in a field simply for temporary
holding then there's no plan for them to eat there and no need to observe
the binding of animal-to-field.  That binding only needs to be checked when
they're trying to eat.
 
> class group [AnimalType <: herbivore] is
>   animals: list [MemberType = AnimalType];
>   fields:  list [MemberType = field [FoodType = AnimalType.FoodType]];
>   function getRipeFood(): AnimalType.FoodType;
> 	   -- get the ripe food from one of its fields.
>   ...
> end group;
> 
> class farm is
>   groups: group;
>   ...
> end farm;
> 
> When you do self farming, you do not need run-time type check or system  
> validation for this well-structured farm:
> 
> procedure self_farming is (f is in farm)
> begin
>   ...
>   for each group in f.groups do
>       for each animal in group do
>           animal.eat(group.getRipeFood ()); -- correct!
> end self_farming.
> 
> I really cannot tell you which way is the best. It depends on the
> requirement of your problem domain. However, a good language should
> provide all the possible ways.

I'd like to know why you didn't address the identification of individual
animals.

For a long time COBOL and FORTRAN were considered "good" languages and
they didn't provide facilities to do these class things.  I guess we
become comfortable with those early developments and begin to take them
for granted.  Now, a good language is soooo much more.

I doubt we're seen a quiescence of language development regarding features
which allow us to develop programs using the OO paradigm.
 
> The language BETA and Cluster come close to what I presented above.
> 
> David Shang

I've not seen BETA and have never heard of Cluster.  Could you provide
a pointer-->ftp_site or other info. about them?  :-)

Finally, I apologize to those who thought my original post was too long at
more than 300 lines.  I thought it necessary to flesh-out the problem at
hand.  In fact, as Mr. Shant points out, it really requires more than I gave.

 
Mark S. Hathaway       <hathawa2@marshall.edu>


======================================================================= 8 ===
Date:    4 Jan 1995 17:03:26 GMT
From:    kalsow@src.dec.com (Bill Kalsow)
Subject: Re: SRC M3 v. 3.4 out

In article <3eegn0$dtp@hermes.unt.edu>, schaub@ponder.csci.unt.edu (Stephen Sch
aub) writes:
> When browsing the Modula-3 home page this morning, I happened to see that
> the current version of the SRC distribution is now 3.4.
> ...
> Did I miss an announcement in this group?

No, you didn't miss the announcement.  I usually let a few people
try out the system before announcing it.  Indeed, they have already
reported a minor bug that I'll fix ASAP.

Yes, 3.4 includes lots of changes:

 - new ports to IRIX 5.2, FreeBSD, and Windows/NT(w/o Trestle)
 - a single top-level, build-everything m3makefile
 - faster compilation (merged driver & pass0)
 - runtime error message that include file and line number
 - m3browser, an HTTP server that provides "virtual Modula-3 space"
 - better shared library support for SOLsun and SPARC
 - more robust type encodings for the debugger (but not Peter Klein's changes)
 - ParseParams and SLisp are back
 - a floating-point version of the geometry package
 - countless bug fixes

If you wait a few days the release will be stable.

 - Bill Kalsow




======================================================================= 9 ===
Date:    Wed, 4 Jan 1995 13:25:57 GMT
From:    kees@dutiag.twi.tudelft.nl (Kees Pronk)
Subject: Question on generics

I have two questions on generics:
In the languge definition in SigPlan 
(and in the book by G. Nelson it says):

#5.5 Generics
#In a generic interface or module, *some* of the imported 
#interfaces are treaded as formal parameters, to be bound 
# to actual interfaces when the generic is instantiated.

It is unclear to me why the *some* is not *all*.
Is this partial instantiation?
There seem to be no examples of this.

In the book by Harbison it is said that (my wording may not 
be exact, as I do not have the book available now):

# There is no need for the interface list of a generic interface 
# to match the interface of its asociated module.

Again there are no examples of such a situation.

Could someone explain the background of these, 
and perhaps provide some examples? (Sorry if this is a faq)

Thanks in advance,
Kees Pronk.

-- 
--------------------------------------------------------
- C. (Kees) Pronk                                
- Delft University of Technology                  
- Fac. of Techn. Math. and Informatics              


======================================================================= 10 ===
Date:    4 Jan 95 09:10:44
From:    dagenais@notung.vlsi.polymtl.ca (Michel Dagenais)
Subject: Re: Which OS for Modula-3


   I have a 486-66 PC with 16Mbyte and a Mitsumi CD ROM.  I want to
   do serious Modula-3 coding (not just try it out a few times).

Hundreds of thousands of lines of M3 code have been compiled on such
platforms so this should be serious enough (m3tk, formsvbt, netobj...).

   What's your recommendation for an OS.  Assume I am busy until midsummer,
   so something available then is ok.  Linux? (Slackware?) OS/2? WinNT?
   FreeBSD?

M3 for LINUX has been working very well for some time. M3 for FreeBSD
recently appeared and is not yet out for newer versions of FreeBSD.
WinNT support may be there by then.
--

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



======================================================================= 11 ===
Date:    4 Jan 95 09:04:37
From:    dagenais@notung.vlsi.polymtl.ca (Michel Dagenais)
Subject: Re: Linux LOCKs

In article <1995Jan3.000902.2586@clio.demon.co.uk> g@clio.demon.co.uk (Gareth W
ebber) writes:

   Is there a problem with the LOCKs set up under Linux M3 version 3.3 as I
   have a program which behaves perfectly (apart from concurrency problems...)
   without locks but as soon as I protect data to remove the concurency issues
   the program gives a deferencing NIL pointer exception. Is this a known
   problem ? I am using the larger of Michael Dagenais's versions.

No known problems in this area. Concurrency is tricky to get right... and
to debug.

   I have heard whispers of a version 3.4. Is there a likely release date ?
   What new features are there ?

No idea for a release date; the longer we wait the more stuff will be
in there :-). The major feature i have heard about is M3 lite, a very
fast compiler for Win32 (Windows NT/ Windows 95) which i will attempt to
get running on Linux.
--

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



======================================================================= 12 ===
Date:    Wed, 4 Jan 1995 15:15:58 GMT
From:    rsutc@twu.ca (Rick Sutcliffe)
Subject: generics

Can anyone here give me a summary of the general consensus on the success
of the generic template facility in Modula-2?  What would you change if
you were designing the facility?  What are its strengths and weaknesses
vis a vis other languages that have generics?
Rick

-- 
Rick Sutcliffe    Assoc. Prof. Computing/Math   Trinity Western University
Canadian Chair, WG13. Not an official spokesperson for TWU or WG13


======================================================================= 13 ===
Date:    4 Jan 1995 16:00:32 GMT
From:    schaub@ponder.csci.unt.edu (Stephen Schaub)
Subject: SRC M3 v. 3.4 out

When browsing the Modula-3 home page this morning, I happened to see that
the current version of the SRC distribution is now 3.4.  According to history,
v 3.4 provides ports for WinNT (without Trestle) and FreeBSD, I believe.  
There was mention of a merging of the m3 front-end and the first compiler
phase, but no word about any other changes (I'd hoped to read that run-time
error messages would include module/line number debugging info, which was
rumored to be an improvement scheduled for release with 3.4). It seems that
the sources are now available via FTP.  Did I miss an announcement in this
group?  Or perhaps I'm just the first one to see it.

Stephen Schaub
schaub@cs.unt.edu


======================================================================= 14 ===
Date:    Wed, 4 Jan 1995 15:14:26 GMT
From:    rsutc@twu.ca (Rick Sutcliffe)
Subject: Sam Harbison???

Can anyone here provide an e-mail address for him?
Thanks
Rick

-- 
Rick Sutcliffe    Assoc. Prof. Computing/Math   Trinity Western University
Canadian Chair, WG13. Not an official spokesperson for TWU or WG13


======================================================================= 15 ===
Date:    Wed, 4 Jan 1995 18:18:54 GMT
From:    rsutc@twu.ca (Rick Sutcliffe)
Subject: Re: generics

In article <rsutc-0401950715580001@nsc189t100.twu.ca>, rsutc@twu.ca (Rick
Sutcliffe) wrote:

> Can anyone here give me a summary of the general consensus on the success
> of the generic template facility in Modula-2?  What would you change if
> you were designing the facility?  What are its strengths and weaknesses
> vis a vis other languages that have generics?
> Rick
> 
> -- 
Whoops  That should of course have been Modula-Three.  I type the other
all the time and it was automatic.
Rick

-- 
Rick Sutcliffe    Assoc. Prof. Computing/Math   Trinity Western University
Canadian Chair, WG13. Not an official spokesperson for TWU or WG13


======================================================================= 16 ===
Date:    04 Jan 1995 17:49:33 GMT
From:    alfh@gyda.ifi.uio.no (Alf-Ivar Holm)
Subject: Re: Cows, Hogs & Farms

In article <1995Jan3.223031@hobbit> hathawa2@marshall.edu (Mark S. Hathaway) wr
ites:

> I've not seen BETA and have never heard of Cluster.  Could you provide
> a pointer-->ftp_site or other info. about them?  :-)

The BETA home page is found at:

	http://www.daimi.aau.dk/~beta/info

I have no info on Cluster.

	Affi


======================================================================= 17 ===
Date:    4 Jan 95 02:27:32
From:    vixie@gw.home.vix.com (Paul A Vixie)
Subject: Re: Is m3 suitable for me ?

I think that you will find Modula-3 uniquely suited for your application.

Because of its separation of interface and implementation, it is an ideal
language for high level simulations where modules of the system being
simulated need to map fairly evenly to modules of the simulator.

I have found that its strong typing and exception support lead to code
that does what it looks like it does, perhaps more so than any other 
language I have used.

But the clinching argument in your case is that you want to animate an
algorythm, and you can thus benefit from the experience of the folks at
SRC, who have done just that, using just this language.  The techreports
database on www.digital.com should have a postscript file of the technical
reports on algorythm animation.  

One thing, though -- graphical programs in Modula-3 don't really teach much
about X Windows since the programming environment isolates those details.
There is no reason in principle why a graphics program in Modula-3 could not
be build on some other system -- as long as the Trestle library had been
implemented for the native windows/graphics system.
--
Paul Vixie
La Honda, CA
<paul@vix.com>
decwrl!vixie!paul


======================================================================= 18 ===
Date:    Wed, 04 Jan 95 13:54:45 -0800
From:    kalsow@pa.dec.com
Subject: Re: Modula-3 Generics 

> * Is the generic facility useful vis a vis other languages?

Yes.  It's more restrictive than what you find in C++ or CLU,
but it's still quite usable.

> * If you could improve it would you?  What would you change?
> * What do you think of having types and constant expressions as parameters
> rather than modules?

Yes, any compile-time constant should be allowed as a parameter
to a generic.  This change would be sound and no problem to implement
in the compiler.

As a programmer, I would like to be able to instantiate a generic
at the point you import it.  For example:

    IMPORT List[CHAR];

But as a compiler writer, I wouldn't be thrilled to implement
the resulting language.

The current m3build system is quite a bit more powerful than make.
It's pretty easy for the author of a generic to provide a build-time
function that produces the little bit of text that Modula-3 requires.
So, here again, the line between programming language and programming
environment is fuzzy.  Where to draw the line is quite subjective.

> * I understand from Sam's book that the interface list for a generic
> interface and for the corresponding generic module are not necessarily the
> same.  Is this correct?

Yes.  For example, see the Modula-3 Sequence generic.  There are
two interfaces (a public and a friends one).  The public interface
is parameterized by the element type's interface, the private interface
is parameterized by the element type and the public interface.  And
finally, the implementation is parameterized by all three.  If you
were able to instantiate generics in import statements this cascading
of generic parameters wouldn't be necessary. 

  - Bill Kalsow




======================================================================= 19 ===
Date:    Wed, 4 Jan 1995 19:19:10 GMT
From:    shang@corp.mot.com (David L. Shang)
Subject: Re: Cows, Hogs & Farms

In article <1995Jan3.223031@hobbit>  writes:
> It appears Mr. Shang has added comp.lang.beta and some other(s) to the
> distribution list.  Perhaps it will expand the conversation to others who
> can enlighten us all.

I think that the BETA and the Modula3 groups are intersted in this subject too.

>  
> > By your herbivore class, you declare that a herbivore can eat any plant.  
> > Therefore, if hog and cow are herbivores, they should eat any plant,
> > otherwise they are not herbivores. If hog and cows are herbivores in the
> > real world, then, your definition of herbivore class is wrong. It makes
> > a false promise on which its subclasses cannot agree.
> 
> If grass and corn are all they will eat then the way I wrote it is correct.
> If they will eat other plants then the constraint that the hog and cow
> should only eat grass and corn aren't defined in those classes then it would
> have to be introduced later.  I wouldn't object to that.  We wouldn't want
> them eating anything dangerous.  :-)

As I said already in my previous posts on the subject of covariance, we cannot 
 
have covariance for a subclass if we cannot find a general rule for that  
subclass. 

If a subclass of herbivore eat all plant (of cause not including poisonous  
plant, which is not a food), you can have:

	AllPlantEatingHerbivore is Herbivore [ FoodType=plant];

If a subclass of herbivore eat all most all plants except for a few plants that
  
you cannot rule out a classification on the food they do not eat, you can have:

	AlmostAllPlantEatingHerbivore is Herbivore [ FoodType=plant];

and use run-time type check to reject those food they do not eat.

If a subclass of herbivore eat only a few plants that you cannot rule out a  
classification on the food they eat, you can also have:

	SomePlantEatingHerbivore is Herbivore [ FoodType=plant];

and use run-time type check to accept those food they eat.

Sometimes multiple inheritance may help the last case to get rid of run-time  
type check.

	class Panda is 	Herbivore [FoodType = BambooLeaf],
			Herbivore [FoodType = Corn]
	      procedure Herbivore[BambooLeaf]::eat (food: BambooLeaf);
	      procedure Herbivore[Corn]::eat (food: Corn);
	end Panda;

In reality, we always have exceptions. We can use covariance to rule out a  
general principle and use run-time type check for a few exceptions. As to the  
animal example, it is clearly worthwhile to divide animals into herbivires,  
carnivores and (?)(animals eating both food) according to the type of their  
food. We can use covaraince. But it might be very hard to rule out a general  
principle for the futher classification for a certain number of animals.  

> > Then, you can have cows and hogs:
> > 
> > class hog is herbivore [FoodType = corn];
> > class cow is herbivore [FoodType = grass];
> 
> Funny how you, too, specify corn & grass as the foods these animals can eat.
> It's the most natural way to describe a HOG or COW.  If there are other
> plants these animals eat then there should be a subset of "plants" created
> for each of them.

We are not developing a commercial software for zoologists, are we? These are  
only padagogical examples. Be wise to make things as simple as possible -- just
  
for the key points you want to say. 

>  
> > If farms are a collection of herbivores with a field where their food
> > grows, we should think about how to model a farm. There are three
> > different ways.
> 
> In the example from the comp.lang.eiffel post there were only HOG & COW and
> an example FARM.  I tried not to stray too far from that.
>  
> > Firstly, you could have a homogeneous farm where only on type of herbivores
> > are raised:
> > 
> > class field [FoodType <: plant]
> >    function getCrop(): FoodType;
> > end field;
> 
> Isn't a generic field which can grow any plant more correct?  Doesn't the
> notation you've given tie one specific plant to the field and not allow for
> future crop rotations?  Farmers plant different crops to avoid depleting the
> soil too much.

This is an abstract field. No object can be intantiated by the class unless you
  
associate it with a plant type.

>  
> > class farm [AnimalType <: herbivore] is
> >   animals: list [MemberType = AnimalType];
> >   fields:  list [MemberType = field [FoodType = AnimalType.FoodType]];
> >   function getRipeFood(): AnimalType.FoodType;
> > 	   -- get the ripe food from one of its fields.
> >   ...
> > end farm;
> > 
> > class hog_farm is herbivore [AnimalType = hog];
> > class cow_farm is herbivore [AnimalType = cow];
> 
> Why would a farm be a herbivore?

Sorry, a typo. Should be:

   class hog_farm is farm [AnimalType = hog];
   class cow_farm is farm [AnimalType = cow];

> 
> I don't care for your syntax which appears to only allow single inheritance.
> What if a COW is not only a HERBIVORE, but a DOMESTICATED_ANIMAL?  I could
> write...
> 
>   class cow is
>     inherit herbivore;
>     inherit domesticated_animal;
>   end cow;
> 

Multiple inheritance is fine:

    class cow is
      		herbivore [FoodType = Grass],
      		domesticated_animal [ FoodType = ManMadeCowFood ];

You can even have:

    class cow is
      		herbivore [FoodType = Grass],
      		herbivore [FoodType = Hay],
      		herbivore [FoodType = Corn],
		...
      		domesticated_animal [ FoodType = ManMadeCowFood ];

Note that herbivore[Grass], herbivore[Hay], ... are anonymous subclasses of  
herbivore and they share the common base of herbivore. 

> Perhaps you're right that I should have developed a generic farm and then
> populated it with particular animals.  That wouldn't be too difficult, as
> you showed.  Again, I wasn't focusing on these peripheral classes as much
> as on the COW and HOG classes and how to build the FARM from them.

Note that the generic classes I presented above are not conventional generic  
classes. You cannot have this by Eiffel's generic class, which is not a real  
class, and hence it is meaningless to discuss the subclass relationship between
  
a generic class and the class instantiated by the generic class.

>  
> > You do not need any run-time type check or system validation for this
> > kind of farm within a close world:
> > 
> > program farming is
> >          c is cow_farm;
> >          h is hog_farm;
> > begin
> >   ...
> >   for each animal in c.animals do animal.eat(aCorn); -- wrong!
> >   for each animal in c.animals do animal.eat(aGrass); -- correct.
> >   for each animal in c.animals do animal.eat (c.getRipeFood ()); 
> >  						-- correct.
> > end farming.
> 
> What if the farmer sells some cows and buys some hogs to have a mixed farm?
> How do you readjust to handle this?

Being owners of homogeneous farms, they cannot have a mixed farm.

Being owners of homogeneous farms, farmers can sell their creatures to a market
  
that accept the type of their creatures:

	cow_farm sells cows to cow market  -- correct
	cow_farm sells cows to hog market  -- incorrect
	cow_farm sells cows to mixed market  -- correct

Being owners of homogeneous farms, farmers can only buy their creatures from a 
 
market sells the type of their creatures:

	cow_farm buys cows from cow market  -- correct
	cow_farm buys cows from hog market  -- incorrect
	cow_farm buys cows from mixed market  -- ensured by run-time type check

The last case must be ensured by a run-time type check, beacuse it is a reverse
  
assignment:

	cow_farm::buy(creature: cow);
	mixed_market::sell():herbivore;

	aCow_farm.buy(aMixed_market.sell()); -- wrong, reverse assignment here!

You should write the code like this:

	a: herbivore := aMixed_market.sell();
	when typeof(a)=cow do aCow_farm.buy(a)
	otherwise aMixed_market.send_back(a);

> > 
> > Secondly, you could have an ill-structured heterogeneous farm where various
  
> > type of herbivores are raised at random fields. That is, there is no  
> > relationship between a field type and a herbivore type:
> > 
> > class farm is
> >   animals: list [MemberType <: herbivore];
> >   fields:  list [MemberType <: field];
> >   function getRipeFood(): plant;
> > 	   -- get the ripe food from one of its fields.
> > end farm;
> 
> Why do you say "animals: list [MemberType <: herbivore];"
> instead of      animals: list [ herbivore ];
> ?
> 

The latter is equivalent to:

	animals: list [ MemberType = herbivore ];

where "animals" is not a polymorphic (heterogeneous) variable.

> And, how does "herbivore" define a COW or HOG when they could easily be
> created from both HERBIVORE and DOMESTICATED_ANIMAL?  What would you do
> in that case?
> 

By multiple inheriatnce as I shown above.


> > You need run-time type check or system validation for this ill-structured
> > farm:
> > 
> > procedure self_farming is (f is in farm)
> > begin
> >   ...
> >   for each animal in f.animals do animal.eat(f.getRipeFood ()); -- wrong!
> >   for each animal in f.animals do 
> > 	plant food := f.getRipeFood();
> > 	when typeof(animal).Foodtype = typeof(food) do
> > 	     animal.eat(food); -- correct
> >   end
> > end self_farming.
> 
> This version of farming() looks pretty good.  I like the use of "typeof()"
> also.  It's quite useful.  My example was difficult to read compared to this.
>  
> > Lastly, you could have an well-structured heterogeneous farm where each
> > type of herbivores are raised at the field that grows their own food. That
> > is, there is a relationship between a field type and a herbivore type:
> 
> But, if an animal (or group of animals) is put in a field simply for 
> temporary
> holding then there's no plan for them to eat there and no need to observe
> the binding of animal-to-field.  That binding only needs to be checked when
> they're trying to eat.
>

There could be a lot of buts. But I don't like to make things unnecessarily  
complicated for the subject discussed here.

David Shang





======================================================================= 20 ===
Date:    Thu, 5 Jan 95 11:07 MET
From:    olaf@logware.de (Olaf Wagner)
Subject: Re: SRC M3 v. 3.4 out


: Yes, 3.4 includes lots of changes:

:  - new ports to IRIX 5.2, FreeBSD, and Windows/NT(w/o Trestle)
:  - a single top-level, build-everything m3makefile
:  - faster compilation (merged driver & pass0)
:  - runtime error message that include file and line number
:  - m3browser, an HTTP server that provides "virtual Modula-3 space"
:  - better shared library support for SOLsun and SPARC
:  - more robust type encodings for the debugger (but not Peter Klein's changes
)
:  - ParseParams and SLisp are back
:  - a floating-point version of the geometry package
:  - countless bug fixes

: If you wait a few days the release will be stable.

Great! 

Just to save you from lots of mail concerning FreeBSD, you should point
out that the version built from the patches I sent you will under no
circumstances run on FreeBSD 2.0 (which is the actual FreeBSD version),
but only on FreeBSD 1.1(.5).

I got the compiler running last week on FreeBSD 2.0, and I will sent you
the patches as soon as possible. There was no way around a new target
(FreeBSD2), and there have been a lot of changes in the Unix-Interfaces.

I'm trying to send you everything before Saturday, before my computer
and everything else will move to a new flat (and won't be connected
for some time...)

Olaf
--
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\ Olaf Wagner              at Logware GmbH       Schwedenstrasse 9     \
\ olaf@logware.de (work)                         13359 Berlin 65       \
\ wagner@luthien.in-berlin.de (private)          Germany / Deutschland \
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\


======================================================================= 21 ===
Date:    Thu, 5 Jan 1995 09:56:33 GMT
From:    olaf@logware.de (Olaf Wagner)
Subject: Re: Which OS for Modula-3

Michel Dagenais (dagenais@notung.vlsi.polymtl.ca) wrote:

:    What's your recommendation for an OS.  Assume I am busy until midsummer,
:    so something available then is ok.  Linux? (Slackware?) OS/2? WinNT?
:    FreeBSD?

: M3 for LINUX has been working very well for some time. M3 for FreeBSD
: recently appeared and is not yet out for newer versions of FreeBSD.
: WinNT support may be there by then.

I got the compiler running on FreeBSD 2.0 last week, after about 20
attempts of cross-comilation. The patches will be send to SRC as soon
as I have some hours time to tidy everything up a bit. The debugger is 
still not compilable. I am trying to integrate the m3-bits of the
m23gdb-release into the gdb port of FreeBSD, but the underlying gdb
versions are quite different.

You may expect something (patches and perhaps a small binary 
distribution) within two or three weeks.

-- 
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\ Olaf Wagner              at Logware GmbH       Schwedenstrasse 9     \
\ olaf@logware.de (work)                         13359 Berlin 65       \
\ wagner@luthien.in-berlin.de (private)          Germany / Deutschland \


======================================================================= 22 ===
Date:    Wed, 04 Jan 95 18:42:55 -0800
From:    heydon@usenet.pa.dec.com
Subject: Re: Question on generics

Kees Pronk asks:

> I have two questions on generics:
>
> In the languge definition in SigPlan (and in the book by G. Nelson
> it says):
>
> # 5.5 Generics
> # In a generic interface or module, *some* of the imported 
> # interfaces are treated as formal parameters, to be bound 
> # to actual interfaces when the generic is instantiated.
> 
> It is unclear to me why the *some* is not *all*. Is this partial
> instantiation? There seem to be no examples of this.

I think you are just forgetting about the interfaces imported
explicitly via IMPORT statements. The names listed as the formal
imports of the generic interface/module are treated as formal
parameters, and the names listed in normal IMPORT statements are not.
For example, in the generic interface:

  GENERIC INTERFACE G(A, B);
  IMPORT C, D, E;
  <interface body>
  END G.

the names "A" and "B" are treated as formal parameters, while the
names "C", "D", and "E" are not. 

> In the book by Harbison it is said that (my wording may not 
> be exact, as I do not have the book available now):
>
> # There is no need for the interface list of a generic interface 
> # to match the interface of its associated module.
>
> Again there are no examples of such a situation.

As Bill Kalsow pointed out in a recent message to comp.lang.modula3,
the generic implementation of Sequences gives an example of this
situation:

> For example, see the Modula-3 Sequence generic. There are two
> interfaces (a public and a friends one). The public interface is
> parameterized by the element type's interface, the private interface
> is parameterized by the element type and the public interface. And
> finally, the implementation is parameterized by all three.

- Allan

--------------------------------------------------------------------
Allan Heydon                           Digital Equipment Corporation
heydon@pa.dec.com                      Systems Research Center
(415) 853-2142                         130 Lytton Avenue
(415) 853-2104 (FAX)                   Palo Alto, CA 94301


======================================================================= 23 ===
Date:    5 Jan 1995 16:36:54 GMT
From:    laszlo@bornholm.ifi.uni-klu.ac.at (Laszlo BOESZOERMENYI)
Subject: Re: Binary files in M3


Have a look at our
SIO (Simple I/O) and SF (Simple Files) interfaces.
The PC-version (compatible to m3 V.2x) is part of the newest release of the
M3PC-Klanegfurt system, just put on the gatekeeper
(announcement comes Monday).
I can send you a version compatible to m3 V.3x, if needed.
(I append the interfaces - they are indepedent from the version).

Best regards
Laszlo Boeszoermenyi

*********************************
*  Prof. Laszlo Boeszoermenyi	*
* Institut fuer Informatik	*
*                              	*
* Universitaet Klagenfurt	*
* Universitaetsstr. 65-67  	*
* A-9022 Klagenfurt / Austria	*
*                              	*
* e-mail:			*
* laszlo@ifi.uni-klu.ac.at	*
* Tel.: 			*	
* 00-43-463-2700-509 		*
* 00-43-463-2700-506 (secr.)	*
* Fax.:		 		*
* 00-43-463-2700-505 		*
*********************************

INTERFACE SIO; (*Simple Input/Output 13.04.94. LB*)

(*SIO provides a Reader and a Writer type.
  A reader or a writer is a stream of typed data.
  Data can be read from a reader by "Get" procedures,
  and can be written by "Put" procedures onto a writer.
  The "Get" and "Put" procedures advance a (hidden) position
  over the reader resp. writer stream.
  The procedure "LookAhead" returns the next character,
  without advancing the reader position.

  All "Put" procedures flush automtically on stdout.
  GetText, GetInt, GetReal, GetBool terminate with any white space character,
  leading whitespaces are ignored. 
  (White spaces are: new line, tab, space, form feed and carriage return.)
  The terminating character is removed from the reader,
  and can be retrieved by the TermChar function.
  "Error" exception is raised only for readers, not connected to Stdio.stdin.
  For Stdio.stdin, the user is prompted to type in a new value.

  SIO provides some additional functions,
  such as positioning (seeking) in readers,
  length and end of readers, flushing of writers etc.
  Writers are strictly sequential, positioning is not supported.
  The default value of the reader or writer parameter is always NIL,
  with the effect, selecting the appropriate standard device.
  Standard reader is Stdio.stdin, which is normally the keyboard.
  Standard writer is Stdio.stdout, which is normally the screen.*)

  IMPORT Rd, Wr;

  EXCEPTION Error;

  TYPE
	 Reader = Rd.T;  (*A Reader is an Rd.T*)
	 Writer = Wr.T;  (*A Writer is a Wr.T*)

  (*--------  Basic procedures  --------*)  

  PROCEDURE GetChar(rd: Reader := NIL): CHAR
	 RAISES {Error};
  (*Returns the next char.*)

  PROCEDURE PutChar(ch: CHAR; wr: Writer := NIL);
  (*Outputs a single character.*)

  PROCEDURE GetText(rd: Reader := NIL): TEXT
	 RAISES {Error};
  (*Reads a text. The terminating character is not appended.*)

  PROCEDURE PutText(t: TEXT; wr: Writer := NIL);
  (*Outputs all characters in t.*)

  PROCEDURE GetLine(rd: Reader := NIL): TEXT
	 RAISES {Error};
  (*Reads a line and returns is as a text. The terminating nl is not appended.*
)

  PROCEDURE PutLine(t: TEXT; wr: Writer := NIL);
  (*Outputs all characters in t and appends a new line.*)

  PROCEDURE GetInt(rd: Reader := NIL): INTEGER
	 RAISES {Error};
  (*Reads a decimal integer.*)

  PROCEDURE PutInt(i: INTEGER; length := 3; wr: Writer := NIL);
  (*Outputs an integer number. 
    The number is right-aligned in a field of length "length", i.e.
    leading blanks are output if the number of digits < "length".*)

  PROCEDURE GetReal(rd: Reader := NIL): REAL
	 RAISES {Error};
  (*Reads a real number.*)

  PROCEDURE PutReal(r: REAL; wr: Writer := NIL);
  (*Outputs a real number. *)

  PROCEDURE GetLongReal(rd: Reader := NIL): LONGREAL
	 RAISES {Error};
  (*Reads a longreal number.*)

  PROCEDURE PutLongReal(r: LONGREAL; wr: Writer := NIL);
  (*Outputs a longreal number. *)

  PROCEDURE GetBool(rd: Reader := NIL): BOOLEAN
	 RAISES {Error};
  (*Reads a Boolean constant, terminated by any character in "terminate".
	 Legal values are: TRUE, True, true, T, t resp. FALSE, False, false, F,
 f.*)
  (*!!! Currently accepts only T, t, F, f due to a bug in "Lex".*)

  PROCEDURE PutBool(b: BOOLEAN; wr: Writer := NIL);
  (*Outputs a Boolean value.*)

  (*--------  Additional procedures  --------*)  

  PROCEDURE LookAhead(rd: Reader := NIL): CHAR
	 RAISES {Error};
  (*Returns the next character, without removing it from the reader.*)

  PROCEDURE TermChar(rd: Reader := NIL): CHAR    
	 RAISES {Error};       
  (*Returns the last terminating character.*)

  PROCEDURE Nl(wr: Writer := NIL);
  (*Outputs a new line.*)

  PROCEDURE PutUnsigned(i: INTEGER; length := 6; base: [2..16] := 16;
                       wr: Writer := NIL);
  (*Outputs an unsigned number with given base.
    The number is right-aligned in a field of length "length".*)

  PROCEDURE End(rd: Reader := NIL): BOOLEAN;
  (*Returns TRUE iff end of reader reached.
	 On the keyborad CTRL-Z on the PC, and CTRL-D in Unix.*)

  PROCEDURE Flush(wr: Writer := NIL);
  (*Flushes the writer on the file. Not necessary for Stdio.stdout.*)

  PROCEDURE Available(rd: Reader := NIL): BOOLEAN;
  (*Returns TRUE iff some characters are available.*)

  PROCEDURE Length(rd: Reader := NIL): CARDINAL;
  (*Returns the length of the reader.
	 Returns 0 if the length cannot be computed.*)

  PROCEDURE Seek(rd: Reader := NIL; position: CARDINAL := 0);
  (*Sets the reader on "position" if it is seekable.
	 Default corresponds to reset a reader.*)

END SIO.

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

INTERFACE SF;  (*SimpleFiles 14.04.94. LB*)

(*SimpleFiles provides simple procedures
  to connect readers and writers with files ("Open" procedures),
  and to decouple them ("Close" procedures).
  "OpenRead" connects a reader to an existing file,
  "OpenWrite" connects a writer to a new file.
  If the file with the given name already exists,
  the user may type in a new name or let it overwrite.
  "OpenAppend" positions the writer at the end of a file.
  The text in parameter "prompt" is displayed on standardout (screen).
  The file connected to a writer is made permanent by a "CloseWrite".

  SimpleFiles provides a flexible mechanism for file naming.
  If the "name" parameter is omitted (or NIL) at opening, then
  the opening procedures ask the user for a file name.
  If the user enters an empty line or Std (actually = "#")
  the file defaults to standard i/o,
  i.e. normally to keyboard (standardin) and screen (standardout).
  "GetFileName" provides more explicit control over file naming. *)

  IMPORT SIO;

  CONST
	 Overwrite   = "!";
         Standard    = "#";
	 PromptStart = "Type file name ";    
	 PromptEnd   = " or NL or for standard = ";
	 InPrompt    = PromptStart & "for  input" & PromptEnd;
	 OutPrompt   = PromptStart & "for output" & PromptEnd;
	 AppPrompt   = PromptStart & "for append" & PromptEnd;

  TYPE
	 Reader = SIO.Reader;
	 Writer = SIO.Writer;

	 
  PROCEDURE OpenRead(name: TEXT := NIL; prompt:= InPrompt): Reader;
  (*Connects the file, called "name" to a reader.
    If "name" is NIL, or the file does not exists,
    it asks the user for a file name until the file can be opened.
    It returns Stdio.stdin if the user enters "return" or Std ("#").*)

  PROCEDURE OpenWrite(name: TEXT := NIL; prompt:= OutPrompt;
                      overwrite:= FALSE): Writer;
  (*Connects a writer to the file, called "name".
    If "name" is NIL it asks the user for a file name.
    It returns Stdio.stdout if the user enters "return" or Std ("#").
    If the file (given in "name" or typed in by the user) already exists,
    and "overwrite" is false, it prompts the user to give another file name 
    or to type constant Overwrite (actually = "!") for overwriting.
    If parameter "overwrite" is true, an existing file with same name
    will be overwritten, without asking the interactive user.*)

  PROCEDURE OpenAppend(name: TEXT := NIL; prompt:= AppPrompt): Writer;
  (*Connects a writer to the file, called "name".
    If "name" is NIL it asks the user for a file name.
    It returns Stdio.stdout if the user enters "return" or Std ("#").
    Creates a new file, if the specifeid file doesn't exist yet.
    If the file already exists, it positions the writer to the end of it.*)
  (*!!! Currently doesn't work on the PC !!! - it doesn't append*)

  PROCEDURE FileExists(name: TEXT): BOOLEAN;
  (*Returns TRUE iff the file exists.*)

  PROCEDURE CloseRead(VAR rd: Reader);
  (*Closes the file. Assigns NIL to rd - except rd is stdin.*)

  PROCEDURE CloseWrite(VAR wr: Writer);
  (*Flushes the writer and closes the file. 
    Assigns NIL to wr - except wr is stdout.
    Close MUST be called if the content of the writer
    should be made permanent!*)

  PROCEDURE GetFileName(prompt:= PromptStart & PromptEnd): TEXT;
  (*Asks the user for a file name - actually a simple text.
    It is the very same procedure used by OpenRead and OpenWrite.*)

END SF.


======================================================================= 24 ===
Date:    5 Jan 1995 21:21:39 GMT
From:    wobber@src.dec.com (Ted Wobber)
Subject: Re: pickle

The current version of pickle uses stack recursion to traverse data structures.
It's possible that you have encountered a stack overflow.  I believe that the
depth limit is fairly small with the default stack size.

If this is the case, there are currently two options:

   1)  increase your stack size,
   2)  write a "pickle special" that iterates through your
           data structure, rather than using recursion.

You can find an example of the latter approach in the ListPkl module in the Net
work
Objects runtime.

Ted Wobber
DEC SRC


======================================================================= 25 ===
Date:    Thu, 5 Jan 1995 18:35:34 GMT
From:    shang@corp.mot.com (David L. Shang)
Subject: Re: Cows, Hogs & Farms

In article <3e07c4$sup@muss.cis.McMaster.CA> u9442202@muss.cis.McMaster.CA  
(E.H. Schnetter) writes:
> OK, here is an example in Sather.  I didn't include much fancy stuff.
> type $HERBIVORE is
>    -- an abstract HERBIVORE
>    name: STR;
>    eat (food: $PLANT);
> end; -- type $HERBIVORE
> 
> class HERBIVORE is
>    -- a general herbivore
>    attr name: STR;
>    create (name: STR): SAME is res::=new; res.name:=name; return res end;
>    eat (food: $PLANT) is raise "HERBIVORE::eat not defined\n" end;
> end; -- class HERBIVORE
> 
> class COW < $HERBIVORE is
>    include HERBIVORE;
>    eat (food: $PLANT) is
>       typecase food
>       when GRASS then
> 	 #OUT + "Cow " + name + " eats " + food.name + "\n";
>       else
> 	 raise "Error: Cow " + name + " cannot eat " + food.name + "\n";
>       end; -- typecase
>    end; -- eat
> end; -- class COW
> 
> class HOG < $HERBIVORE is
>    include HERBIVORE;
>    eat (food: $PLANT) is
>       typecase food
>       when CORN then
> 	 #OUT + "Hog " + name + " eats " + food.name + "\n";
>       else
> 	 raise "Error: Hog " + name + " cannot eat " + food.name + "\n";
>       end; -- typecase
>    end; -- eat
> end; -- class HOG
>    
> type $PLANT is
>    -- an abstract plant
>    name: STR;
> end; -- type $PLANT
> 
> class PLANT is
>    -- a general plant
>    const name: STR := "general plant";
>    create: SAME is return new end;
> end; -- class PLANT
> 
> class GRASS < $PLANT is
>    include PLANT;
>    const name: STR := "grass";
> end; -- class GRASS
> 
> class CORN < $PLANT is
>    include PLANT;
>    const name: STR := "corn";
> end; -- class CORN
>    
> class FARM is
>    
>    attr livestock: ARRAY{$HERBIVORE}; -- cows and hogs
>    attr foodstuff: ARRAY{$PLANT}; -- grass and corn
>    
>    main is
>       -- Set up the farm
>       livestock := |#COW("Elsa"), #HOG("Peter Pan")|;
>       foodstuff := |#GRASS, #CORN|;
>       -- Feed everything to everyone
>       loop			-- all the food
> 	 food::=foodstuff.elt!;
> 	 loop			-- all the animals
> 	    protect
> 	       -- try to feed...
> 	       livestock.elt!.eat(food);
> 	    when STR then
> 	       -- oops, went wrong
> 	       #OUT + exception;
> 	    end; -- protect
> 	 end; -- loop animals
>       end; -- loop food
>    end; -- main
>    
> end; -- class FARM
> 

What you presented here is "Invaraince + Runtime Type Check", not a covariance.

At a hogsty, if there is a plate saying "please feed me any plant", what will  
hapen? The sty will be full of rotten food that the hog does not eat.

The plate should say "please feed me corn only". That is, the eat interface  
should tell its feeder the right food (if we suppose that a hog eat corn only).

I'm not syaing that an interface should always tells the exact type. It depends
  
on the desired semantics for that function.

"eat" definitely needs an exact interface:

	hog eats corns only  -- covariance

"try" may have a vaguer interface:

	hog try all plant  -- invaraince + runtime type check

As I always said, a good language should provide all the possiblities.

When hog knows "x" is a corn, it should be able to eat "x" without run-time  
type check:

	cornstuff: list[corn];
	aHog.eat (cornstuff.first);

When a herbivore knows "x" is the food that it eats, it should be able to eat  
"x" without run-time type check:

	[HerbivoreType <: herbivore]
	(  aHerbivore:  HerbivoreType;
	   food:	HerbivoreType.FoodType
	)
	enter
		aHerbivore.eat(food);
	end;

But by Sather, run-time type check is always a neccessity. And by Eiffel's  
covariance, a system validation is required for the above case.

By Cluster, runtime type check is not necessary for the above cases. It is only
  
necessary when a herbivore cannot identify whether the food is its food. This  
happens only in the case of a reverse/cross assignment:

	foodstuff: list[plant];
	...
	aHog.eat (cornstuff.getfirst()); -- wrong! reverse assignment here

	-- We should use run time type check here:
	for each food in foodstuff do
	{	when typeof(food) is corn do
		{    aHog.eat(food);
		     break;
		}
	}

Run time type check can also be encapsulated by a hog's method, say "try":

	function hog::try(food: plant): plant
	enter
		when typeof(food) is corn do 
		{	eat (food);
			return nil;
		}
		return food;
	end;

Back to the original example when both the food type and the animal type are  
unknown:

	livestock: list[herbivore];
	foodstuff: list[plant];
	...
	livestock.getfirst().eat (foodstuff.getfirst());
		  -- wrong! cross assignment here

	-- we should write code like this:
	hungry:   list[herbivore] = {};
	unused:   list[plant] = {};
	for each animal in livestock do
	{
	    for each food in foodstuff do
	    {  
		food:= animal.try(food);
		if food<>nil then
		{   for each animal in hungry do
		    {
			food:= animal.try(food);
			if food=nil then
			{	hungry.remove(animal);
				break;
			}
		    }
		    if food<>nil then unused.add(food)
		} else
		{   animal := nil;
		    break;
		}
	    }
	    if (animal<>nil) then
	    {   for each food in unused do
		{
			food:= animal.try(food);
			if food=nil then
		        {	unused.remove(food);
				animal:=nil;
				break;
			}
		}
		if animal<>nil then hungry.add(animal);
	    }		
	}

>From the above example, we can see that a  runtime type mismaych is not  
necessarily an exception, nor a type error. The system is designed this way. It
  
is the desired semantics.

What is a type error? A type error happens only when the type voilates the  
requirement of the interface specification.

	hog eats grass

is a type error, but

	hog tries grass

is not a type error.

Runtime type check is not an very important issue. The keypoint is that whether
  
the language can say the way you want!

David Shang






======================================================================= 26 ===
Date:    Thu, 5 Jan 1995 19:17:51 GMT
From:    shang@corp.mot.com (David L. Shang)
Subject: Cluster -- wsa Re: Cows, Hogs & Farms

In article <ALFH.95Jan4184933@gyda.ifi.uio.no> alfh@gyda.ifi.uio.no (Alf-Ivar  
Holm) writes:
> In article <1995Jan3.223031@hobbit> hathawa2@marshall.edu (Mark S. Hathaway) 
 
writes:
> 
> > I've not seen BETA and have never heard of Cluster.  Could you provide
> > a pointer-->ftp_site or other info. about them?  :-)
> 
> The BETA home page is found at:
> 
> 	http://www.daimi.aau.dk/~beta/info
> 
> I have no info on Cluster.
> 
> 	Affi

Cluster: An Informal Report. SIGPLAN Notices 26:1(1991) 57-76.

Towards a Combinative Distributed OS in Cluster. IEEE CS Proc. 10th Intl.
Conf. on Distributed Computing Systems, Paris, May, 1990.

Type-Safe Reuse of Prototype Software. Proc. of 3rd SEKE Intl. Conf.
Skokie, Illinois, 1991.

Covariant Specification. SIGPLAN Notices 29:12(1994) 58-65.

Covariant Deepsubtyping Reconsidered. Unpulished.

Cluster in implemented under the DOS version in 1987.

I don't consider Cluster is an execellent practical programming language. I  
completely redefined the object-oriented terminology and use an hermetic  
syntax, which makes the language hard to understand and to use. However, there 
 
are a number of new concepts which are useful for bridging the gap between the 
 
static and dynamic typing systems, for dealing with covariant deep subtyping  
safely, and for programming at a meta level to create, for example, various  
concurrent models, various object storage protocols, and so on.

In the recent years of my study on various other OOPLs, I found that Cluster's 
 
concepts can be integrated with common notions very well. I am in the redesign 
 
of the language -- Cluster-2 -- or some other name. It is not just another  
language added to the pile.

The sytax and semantics of the new language will be a natual extension to  
ordinary languages. The basic sytax will be Pascal-like with some C/C++'s  
convnient feature. But the expanded sytax and semantics will be far beyond the 
 
Pascal/C++ language.

Just an example to show a little bit of the langauge style:

	function foo (input1: Type1; input2: Type2): OutputType
	declare
		// local declarations here
	enter
		// function body here;
	end;

I use "enter" instead of "begin" because "enter" is not a counterpart of "end",
  
rather, is in the equal position of "declare".

People who knows Pascal will have a smooth transition to the above format.  
However, for people who want to explore a more flexible structure, they have to
  
learn more.

Firstly, when we say that "foo" is a "function", we actually mean that "foo" is
  
a class and its superclass is "function". Therefore, language users can design 
 
their own super "function" classes like "process", "thread", "task",  
"remoteProcedure", "DatabaseTransaction", and so on. And then, they can have:

	process foo (input1: Type1; input2: Type2): OutputType
	declare
		// local declarations here
	enter
		// function body here;
	end;

Calling "foo" will create a process.

Secondly, the above format is a simple format from a more general format for a 
 
class:

	class foo is function
	declare
		// local declarations here
	enter (input1: Type1; input2: Type2): OutputType
		// function body here;
	end;

You can have multiple input interfaces:

	class foo is function
	declare
		// local declarations here
	enter (input1: Type1): OutputType
		// function body1 here;
	enter (input1: Type1; input2: Type2): OutputType
		// function body2 here;
	end;

Thirdly, class can be nested. You can have something like:

	class foo is task
	declare
		// local declarations of variables shared
		// by multiple threads
	   thread thd1 ( ... )  // local class declaration
	   enter
		// thd1 code
	   end;
	   thread thd2 ( ... )
	   enter
		// thd2 code
	   end;
	   ...
	enter ( (*input for task creation*) )
		// tast initialization code;
	end;

Note that both "task" and "thread" are user-defined classes. This is a simular 
 
form of a class declaration:

	class foo is object
	declare
		// local declarations of variables shared
		// by methods
	   method mhd1 ( ... )
	   enter
		// mhd1 code
	   end;
	   method mhd2 ( ... )
	   enter
		// mhd2 code
	   end;
	   ...
	enter ( (*input for task creation*) )
		// object construct (initilization) code;
	end;

The difference is that the later is sequential while the fommer is concurrent. 
 
The key point is that the language does NOT provide built-in features like  
"thread", "method", rather, it provides only the framework to build those  
features. And this framework is uniformed by the class concept.

Lastly, class can be parameterized. And the supported parameterization is not  
the coventional one, though the syntax is very similar to Eiffel's generic  
class. Generic classes are real classes and are fully interagted into the type 
 
system.

David Shang








======================================================================= 27 ===
Date:    6 Jan 1995 04:31:34 GMT
From:    mbk@inls1.ucsd.edu (Matt Kennel)
Subject: Re: Cows, Hogs & Farms

David L. Shang (shang@corp.mot.com) wrote:

: But by Sather, run-time type check is always a neccessity. And by Eiffel's  
: covariance, a system validation is required for the above case.

: By Cluster, runtime type check is not necessary for the above cases. It is on
ly  
: necessary when a herbivore cannot identify whether the food is its food. This
  
: happens only in the case of a reverse/cross assignment:

:<deleted>

: Runtime type check is not an very important issue. The keypoint is that wheth
er  
: the language can say the way you want!

: David Shang

You can do most of Cluster's static solution in Sather, and I guess Eiffel.

type $HERBIVORE is
	-- generic herbivore, no specific foodtype known.
	name:STR;
	eat_or_barf(food:$PLANT);

type $HERBIVORE{FOODT < $PLANT} < $HERBIVORE is
	name:STR;
	eat(food:FOODT)  -- must be able to eat
end;

class COW < $HERBIVORE{GRASS} is
	-- blah blah
end;

class HOG < $HERBIVORE{CORN} is
	-- blah blah
end;

class MONOCULTUREFARM{FOODT, ANIMALT < $HERBIVORE{FOODT} }  is
	attr livestock : LIST{ANIMALT};  -- type is known at compile time
	attr foodstock : LIST{FOODT};	 -- type is known 

	dinnertime is
	    loop
		elsie ::= livestock.elt!;
		dinner ::= foodstock.elt;

		elsie.eat(dinner);	-- sooouie! no run-time check needed.
	    end;
	end;
end;

class FREEFORMFARM is
	attr livestock : LIST{$HERBIVORE};
	attr foodstock : LIST{$PLANT};

	dinnertime is 
	    loop
		animal ::= livestock.elt!;
		dinner ::= foodstock.elt!;

		animal.eat_or_barf(dinner);  -- run-time check in there.
	    end;
	end;

end;


In Cluster I guess, you could have written MONOCULTUREFARM with
just one type parameter (the ANIMAL) and then extract its preferred
food from that.  You can't do that in Sather I don't think but
there isn't so much harm, as it's a compile time error to instantiate it
with a bad combination of herbivore and food.

cheers
Matt

--
-Matt Kennel  		mbk@inls1.ucsd.edu
-Institute for Nonlinear Science, University of California, San Diego
-*** AD: Archive for nonlinear dynamics papers & programs: FTP to
-***     lyapunov.ucsd.edu, username "anonymous".


======================================================================= 28 ===
Date:    Thu, 5 Jan 1995 12:09:46 GMT
From:    skj@oasis.icl.co.uk (Simon Johnston)
Subject: Re: SRC M3 v. 3.4 out

Bill Kalsow (kalsow@src.dec.com) wrote:
: In article <3eegn0$dtp@hermes.unt.edu>, schaub@ponder.csci.unt.edu (Stephen S
chaub) writes:
: > Did I miss an announcement in this group?

: No, you didn't miss the announcement.  I usually let a few people
: try out the system before announcing it.  Indeed, they have already
: reported a minor bug that I'll fix ASAP.

Damn good idea IMHO.

: Yes, 3.4 includes lots of changes:
:  - new ports to IRIX 5.2, FreeBSD, and Windows/NT(w/o Trestle)

WNT?!? - I am a die hard OS2 developer (have been for 4+ years), weve been 
crying for an OS2 port for some time, though noone has had enough time. Could 
I ask what compiler youre using for WNT?, could we see a SRC OS2 version?

:  - a single top-level, build-everything m3makefile
:  - faster compilation (merged driver & pass0)
:  - runtime error message that include file and line number

All good.

:  - m3browser, an HTTP server that provides "virtual Modula-3 space"

Uh ?

:  - better shared library support for SOLsun and SPARC

Howabout Linux?

:  - more robust type encodings for the debugger (but not Peter Klein's changes
)
:  - ParseParams and SLisp are back
:  - a floating-point version of the geometry package
:  - countless bug fixes

All sounds good.

: If you wait a few days the release will be stable.

I can wait.


======================================================================= 29 ===
Date:    6 Jan 1995 10:12:29 GMT
From:    olevi@daimi.aau.dk (Ole Villumsen)
Subject: Re: Cows, Hogs & Farms

I haven't followed (nor understood) the entire discussion.
But as far as I can see, Beta does not have the problem Sather
is claimed to have.

  herbivore: (# foodType:< plant; (* virtual type *)
                eat: (# someFood: ^foodType;
                     enter someFood[]
                     do ...
                     #);
             #);

  cow: herbivore (# foodType::< grass; (* further binding the virtual *)
                 #);

  hog: herbivore (# foodType::< corn; #);

Now we can go (assuming the variables are declared with the expected types:
someGrass: ^grass; somePlant: ^plant; etc.):

  someGrass[] -> &aCow.eat; (* o.k.; typechecked at compile-time *)

  someGrass[] -> &aHog.eat; (* error, reported by compiler *)

  somePlant[] -> &aCow.eat; (* compiler will insert a runtime type check *)

  someCorn[] -> &aHerbivore.eat; (* again, runtime type check *)

  (if somePlant## // grass## then somePlant[] -> &aCow.eat;
                  // corn##  then somePlant[] -> &aHog.eat;
  else ...
  if);

How's that? (The compiler will insert runtime type checks in the last
example, unless you instruct it not to; maybe future versions of the
compiler will be smart enough to "see" that it's not necessary.)

Ole


======================================================================= 30 ===
Date:    6 Jan 1995 19:01:26 GMT
From:    kalsow@src.dec.com (Bill Kalsow)
Subject: Re: SRC M3 v. 3.4 out

In article <D1xLsC.6ss@oasis.icl.co.uk>, skj@oasis.icl.co.uk (Simon Johnston) w
rites:
> : Yes, 3.4 includes lots of changes:
> :  - new ports to IRIX 5.2, FreeBSD, and Windows/NT(w/o Trestle)
> 
> WNT?!? - I am a die hard OS2 developer (have been for 4+ years), weve been 
> crying for an OS2 port for some time, though noone has had enough time. Could
 
> I ask what compiler youre using for WNT?, could we see a SRC OS2 version?

We use the Microsoft C compiler included in the NT/SDK for
the few pieces of the system that are C.  The Modula-3 source
code is compiled directly to object code, none of the

 M3 -> IL -> gcc-tree -> RTL -> asm -> object

nonsense that we use on Unix.

Given our resource limits, we cannot port the system to all platforms.
So far, we've only ported it to DS3100, ALPHA_OSF and NT386.  All other
ports were done outside SRC.  A year ago we decided Chicago would be the
next platform we targeted.  NT was ready first, so we used it.

I don't have any particular bias for or against OS/2.  Given the number
of people grumbling, somebody should port M3 to OS/2.  I don't know
why it hasn't happened yet.

> :  - m3browser, an HTTP server that provides "virtual Modula-3 space"
> 
> Uh ?

The browser is an HTTP server that provides WWW access to your
installed Modula-3 system.  It lets you browse and search in
the module and type name spaces.

> :  - better shared library support for SOLsun and SPARC
> 
> Howabout Linux?

It's hard to keep up with the changes in Linux.  We don't do much
of the work for M3/Linux, we just distribute what others tell us.


 - Bill Kalsow



======================================================================= 31 ===
Date:    Fri, 6 Jan 1995 16:49:48 GMT
From:    shang@corp.mot.com (David L. Shang)
Subject: Re: Cows, Hogs & Farms

In article <3eih36$94g@network.ucsd.edu> mbk@inls1.ucsd.edu (Matt Kennel)  
writes:

> 
> You can do most of Cluster's static solution in Sather, and I guess Eiffel.
> 
> ...
> class MONOCULTUREFARM{FOODT, ANIMALT < $HERBIVORE{FOODT} }  is
> 	attr livestock : LIST{ANIMALT};  -- type is known at compile time
> 	attr foodstock : LIST{FOODT};	 -- type is known 
> ...

My guess is that Eiffel can have a similar expression in its contrained generic
  
class. How about Modula-3 and Ada9x's generic class?

This form is slightly different in semantics from the Cluster's form:

  class MONOCULTUREFARM  [ANIMALT <: HERBIVORE]
 	attr livestock : list[ANIMALT];
 	attr foodstock : list[ANIMALT.FOODT]; 
							----- (1)

or BETA's form:

  MONOCULTUREFARM
	(#   ANIMALT :< HERBIVORE
 	     attr livestock : @list (# eleT::ANIMALT #);
 	     attr foodstock : @list (# eleT::ANIMALT.FOODT #); 
	#)

However, Cluster can provide the equivalent form to your Sather's vertion.

There is a major difference between Cluster/BETA's generic class and Sather's. 
 
I'll discuss the major difference later.

We first discuss the minor difference you mentioned:

> In Cluster I guess, you could have written MONOCULTUREFARM with
> just one type parameter (the ANIMAL) and then extract its preferred
> food from that.  You can't do that in Sather I don't think but
> there isn't so much harm, as it's a compile time error to instantiate it
> with a bad combination of herbivore and food.
> 

Sometimes we should use two type parameters (in Cluster):

  class MONOCULTUREFARM  [FOODT <: FOOD; ANIMALT <: HERBIVORE[FOODT]]
 	attr livestock : list[ANIMALT];
 	attr foodstock : list[FOODT]; 
							----- (2)

or sometimes we should use:

  class MONOCULTUREFARM  [FOODT <: FOOD]
 	attr livestock : list[<:ANIMAL[FOODT]];
 	attr foodstock : list[FOODT]; 
							----- (3)

Semantics of (1), (2) and (3) are different.

The first one means a farm with a set of animals of the same type, where a  
foodstock is provided to hold the food that those animals can eat.

The second one mean a farm with a set of animals that eat the same food, and a 
 
foodstock is provided to hold the food. Those animals are not necessararily in 
 
the same type. Thus you can have a farm with mixed cows and sheeps.

The third one mean farm with a foodstock, where a number of animals that eat  
its food are raised. It is basically the same as the second one: those animals 
 
are not necessararily in the same type. Thus you can put mixed cows and sheeps 
 
into the farm.

The first one lay its stress on animals: farms are classified by animals. The  
food type is a dependent type to the animal type that the farm has.

The last two lay their stress on food: farms are classified by food types. The 
 
animal type is a dependent type to the food type that the farm has.

It might be difficult to argue which way is better for a farm, but as I said,  
the language should at least give the way that the speaker wants.

Back to the major differece: Cluster's generic class are real classes but  
Sather's is not. Therefore, by Cluster, HERBIVORE[GRASS] is a subclass/subtype 
 
of HERBIVORE. By Sather, HERBIVORE[GRASS] cannot be a subclass/subtype of  
HERBIVORE. That's whay Sather cannot have the expression:

	ANIMALT < $HERBIVORE

because HERBIVORE is not a class.

What raised by the original post is really a covariance issue. Without the  
subclass relationship, it is meaningless to discuss the covariant relationship 
 
between COW/HOG and HERBIVORE in a type theory.

Another drawback of Sather's generic class is that it cannot support a dynamic 
 
polymorphism or runtime binding based on class paramenters. Therefore, it is  
impposible to use Sather to specify a HETERCULTUREFARM composed of a number of 
 
MONOCULTUREFARMs -- a farm I called well-structured heterogeneous farm in my  
previous post. Runtime type check should be unnecessary for self-farming in  
this heterogeneous farm.

David Shang







======================================================================= 32 ===
Date:    6 Jan 95 19:18:22
From:    nayeri@gte.com (Farshad Nayeri)
Subject: Re: Question on generics


In article <9501062053.AA19195@spieler.pa.dec.com> Alan Heydon
(heydon@usenet.pa.dec.com) points out where the sequence package
resides.

You can also view the sequence implementation or other SRC Modula-3
sources via anonymous ftp from ftp.vlsi.polymtl.ca, directory
/lude/modula-3.34/run/poly/sun4.1_sparc/lib/m3/pkg.

The URL for the sequence directory is:

   ftp://ftp.vlsi.polymtl.ca
   /lude/modula3-3.4/run/poly/sun4.1_sparc/lib/m3/pkg/libm3/src/sequence

Another version of the sources with hyprtext markups exist within Bill
Kalsow's Alphabetical Index for Modula-3 interfaces. See the SRC
Modula-3 entry under the Modula-3 Mosaic Home Page for more
information.

-- Farshad
--
Farshad Nayeri
nayeri@gte.com


======================================================================= 33 ===
Date:    06 Jan 1995 19:51:22 GMT
From:    nayeri@gte.com (Farshad Nayeri)
Subject: Re: SRC M3 v. 3.4 out

In article <3eekcu$avv@src-news.pa.dec.com> kalsow@src.dec.com (Bill Kalsow) wr
ites:

> > Did I miss an announcement in this group?
> 
> No, you didn't miss the announcement.  I usually let a few people
> try out the system before announcing it.  Indeed, they have already
> reported a minor bug that I'll fix ASAP.
> 
> Yes, 3.4 includes lots of changes: 
>
> [many wonderful additions and changes deleted.]

A few of us have been testing the system to check for minor problems
before it goes "public". I am happy to report that everything has been
very smooth on SPARCs.  (As Bill says, however, please wait until he
announces it, as some of the minor changes haven't made it back to the
release.)

The compiler has been overhauled and the libraries re-organized, a
couple of important architectures have been added. Yet, everything
seems to work just fine. SRC Modula-3 is cleaner, much easier to
install, more portable, and faster (at least on SPARCs).

I'd like to take this chance to commend Bill Kalsow and the rest of
the people at SRC who helped with the SRC Modula-3 distribution for
doing such a great job!

-- Farshad
--
Farshad Nayeri
nayeri@gte.com


======================================================================= 34 ===
Date:    7 Jan 1995 00:31:37 GMT
From:    mbk@inls1.ucsd.edu (Matt Kennel)
Subject: Re: Cows, Hogs & Farms

David L. Shang (shang@corp.mot.com) wrote:

: Sometimes we should use two type parameters (in Cluster):

:   class MONOCULTUREFARM  [FOODT <: FOOD; ANIMALT <: HERBIVORE[FOODT]]
:  	attr livestock : list[ANIMALT];
:  	attr foodstock : list[FOODT]; 
: 							----- (2)

: or sometimes we should use:

:   class MONOCULTUREFARM  [FOODT <: FOOD]
:  	attr livestock : list[<:ANIMAL[FOODT]];
:  	attr foodstock : list[FOODT]; 
: 							----- (3)

: Semantics of (1), (2) and (3) are different.

: The first one means a farm with a set of animals of the same type, where a  
: foodstock is provided to hold the food that those animals can eat.

: The second one mean a farm with a set of animals that eat the same food, and 
a  
: foodstock is provided to hold the food. Those animals are not necessararily i
n  
: the same type. Thus you can have a farm with mixed cows and sheeps.

Ok you could do this in Sather by just saying

illinois: MONOCULTUREFARM{GRASS,$HERBIVORE{GRASS}}

and so the animals in 'illinois' would be anything that could eat grass.

: The third one mean farm with a foodstock, where a number of animals that eat 
 
: its food are raised. It is basically the same as the second one: those animal
s  
: are not necessararily in the same type. Thus you can put mixed cows and sheep
s  
: into the farm.

: The first one lay its stress on animals: farms are classified by animals. The
  
: food type is a dependent type to the animal type that the farm has.

: The last two lay their stress on food: farms are classified by food types. Th
e  
: animal type is a dependent type to the food type that the farm has.

: It might be difficult to argue which way is better for a farm, but as I said,
  
: the language should at least give the way that the speaker wants.

Right it's a limitation that the generic type parameter is nameless.

: Back to the major differece: Cluster's generic class are real classes but  
: Sather's is not. Therefore, by Cluster, HERBIVORE[GRASS] is a subclass/subtyp
e  
: of HERBIVORE. By Sather, HERBIVORE[GRASS] cannot be a subclass/subtype of  
: HERBIVORE. That's whay Sather cannot have the expression:

: 	ANIMALT < $HERBIVORE

: because HERBIVORE is not a class.

OK.  But you could write a type $HERBIVORE > $HERBIVORE{FOODT} that
specified just those features not dependent on FOODT (say
"eat_or_barf(x:$PLANT)"), and so all COW's and HOG's could be a subclass of
some $HERBIVORE, if somewhere else you needed to classify ANIMAL's on the
basis on whether or not they were an $HEBIVORE.

: What raised by the original post is really a covariance issue. Without the  
: subclass relationship, it is meaningless to discuss the covariant relationshi
p  
: between COW/HOG and HERBIVORE in a type theory.

: Another drawback of Sather's generic class is that it cannot support a dynami
c  
: polymorphism or runtime binding based on class paramenters. 
: Therefore, it is  
: impposible to use Sather to specify a HETERCULTUREFARM composed of a number o
f  
: MONOCULTUREFARMs -- a farm I called well-structured heterogeneous farm in my 
 
: previous post. Runtime type check should be unnecessary for self-farming in  
: this heterogeneous farm.

What is this exactly?  I guess I don't quite see.

Sather and Eiffel et cetera are statically typed in this sense:
there is no notion of a variable which contains a "type" that can be
modified at run-time, and new objects made in a fashion which depend on this
run-time type as a generic parameter. 

I guess I don't quite understand the implications or meaning of when
this is not the case.

All type parameters must be resolved at compile time;
there must be some performance benefit, yes?

For example if you have run-time computatble types, you have to conceivably
deal with all legal specializations of some generic type, for the type
parameter might be some value comptuted at run-time which in general
might be unknown.

: David Shang

--
-Matt Kennel  		mbk@inls1.ucsd.edu
-Institute for Nonlinear Science, University of California, San Diego
-*** AD: Archive for nonlinear dynamics papers & programs: FTP to
-***     lyapunov.ucsd.edu, username "anonymous".


======================================================================= 35 ===
Date:    06 Jan 1995 21:06:20 GMT
From:    schwartz@galapagos.cse.psu.edu (Scott Schwartz)
Subject: Re: SRC M3 v. 3.4 out

nayeri@gte.com (Farshad Nayeri) writes:
   SRC Modula-3 is cleaner, much easier to install, more portable, and
   faster (at least on SPARCs).

Has the runtime system gotten any smaller?


======================================================================= 36 ===
Date:    Fri, 6 Jan 1995 18:44:58 GMT
From:    rsutc@twu.ca (Rick Sutcliffe)
Subject: Re: Question on generics

In article <9501050242.AA08630@spieler.pa.dec.com>,
heydon@usenet.pa.dec.com wrote:

> As Bill Kalsow pointed out in a recent message to comp.lang.modula3,
> the generic implementation of Sequences gives an example of this
> situation:
> 
> > For example, see the Modula-3 Sequence generic. There are two
> > interfaces (a public and a friends one). The public interface is
> > parameterized by the element type's interface, the private interface
> > is parameterized by the element type and the public interface. And
> > finally, the implementation is parameterized by all three.
> 
Could you point us to where this example is, please.
Rick

-- 
Rick Sutcliffe    Assoc. Prof. Computing/Math   Trinity Western University
Canadian Chair, WG13. Not an official spokesperson for TWU or WG13


======================================================================= 37 ===
Date:    Fri, 06 Jan 95 12:53:31 -0800
From:    heydon@usenet.pa.dec.com
Subject: Re: Question on generics

> Could you point us to where this [Sequence] example is, please.

The generic Sequence interfaces and implementations live in the
package named "sequence":

  heydon> ls /proj/m3/pkg/sequence/src
  Sequence.ig     Sequence.mg     gen.sh          sequence.tmpl
  Sequence.lm3    SequenceRep.ig  m3makefile      string.lsl

To read them, you need to have installed v3.X of the Modula-3
distribution. If you don't have the Modula-3 distribution, see the
Modula-3 FAQ for instructions on how to FTP it from
gatekeeper.dec.com.

- Allan

--------------------------------------------------------------------
Allan Heydon                           Digital Equipment Corporation
heydon@pa.dec.com                      Systems Research Center
(415) 853-2142                         130 Lytton Avenue
(415) 853-2104 (FAX)                   Palo Alto, CA 94301


======================================================================= 38 ===
Date:    Sat, 7 Jan 1995 10:20:52 -0500
From:    Philip Siming Zhan <szhan@watdragon.uwaterloo.ca>
Subject: How to install M3?

I just got the src files for M3 compiler, lib, etc., for Linux 
from sunsite FTP site. (src-m3-3.3l2.strip.tar.gz, m3gdb.tgz and 
*.lsm and *.html files). After uncompressed the files, I found
out that there are pre-compiled binaries, src files and lib files. 
BUT there is no instruction how to install the packages (setup 
the path and env variables, etc.).  Is it enough just by setting 
binaries file path? 

I am new to M3 (taking the course this semester). 

Phil



======================================================================= 39 ===
Date:    Sat, 7 Jan 1995 15:20:51 GMT
From:    szhan@watdragon.uwaterloo.ca (Philip Siming Zhan)
Subject: How to install M3?

I just got the src files for M3 compiler, lib, etc., for Linux 
from sunsite FTP site. (src-m3-3.3l2.strip.tar.gz, m3gdb.tgz and 
*.lsm and *.html files). After uncompressed the files, I found
out that there are pre-compiled binaries, src files and lib files. 
BUT there is no instruction how to install the packages (setup 
the path and env variables, etc.).  Is it enough just by setting 
binaries file path? 

I am new to M3 (taking the course this semester). 

Phil



======================================================================= 40 ===
Date:    8 Jan 1995 11:34:59 GMT
From:    and1000@cus.cam.ac.uk (Austin Donnelly)
Subject: Re: Linux LOCKs

In article <DAGENAIS.95Jan4090437@notung.vlsi.polymtl.ca>,
Michel Dagenais <dagenais@notung.vlsi.polymtl.ca> wrote:
>In article <1995Jan3.000902.2586@clio.demon.co.uk> g@clio.demon.co.uk
>(Gareth Webber) writes:
>
>   Is there a problem with the LOCKs set up under Linux M3 version 3.3 as I
>   have a program which behaves perfectly (apart from concurrency problems...)
>   without locks but as soon as I protect data to remove the concurency issues
>   the program gives a deferencing NIL pointer exception. Is this a known
>   problem ? I am using the larger of Michael Dagenais's versions.
>
>No known problems in this area. Concurrency is tricky to get right... and
>to debug.
>

At a wild guess, are you using NEW() to get yourself a mutex? Eg:

VAR mu:= NEW(MUTEX);

LOCK mu
  (* burble *)
END;

Since MUTEX <: ROOT, it needs storage allocated on the heap
for it.


Austin


======================================================================= 41 ===
Date:    9 Jan 95 00:56:27 EDT
From:    hathawa2@marshall.edu (Mark S. Hathaway)
Subject: Re: Cows, Hogs & Farms

> In article <1995Jan6.164948.4782@schbbs.mot.com>,
> shang@corp.mot.com (David L. Shang) writes:

>> In article <3eih36$94g@network.ucsd.edu>
>> mbk@inls1.ucsd.edu (Matt Kennel) writes:

>> ...

>> You can do most of Cluster's static solution in Sather, and I guess Eiffel.
>> 
>> ...
>> class MONOCULTUREFARM{FOODT, ANIMALT < $HERBIVORE{FOODT} }  is
>> 	attr livestock : LIST{ANIMALT};  -- type is known at compile time
>> 	attr foodstock : LIST{FOODT};	 -- type is known 
>> ...

Should there be a $FOOD abstract type used here ( "FOODT < $FOOD" )?
Would there have to be an "include HERBIVORE" and maybe "include FOOD"
for this to work?  How would that be done?


> This form is slightly different in semantics from the Cluster's form:
> 
>   class MONOCULTUREFARM  [ANIMALT <: HERBIVORE]
>  	attr livestock : list[ANIMALT];
>  	attr foodstock : list[ANIMALT.FOODT]; 
> 							----- (1)

Does Cluster separate the subtyping and inheritance as Sather does?

Is the use of "ANIMALT <: HERBIVORE" a convenience or requirement?

So, ANIMALT.FOODT implies that a particular food is associated with a
particular animal?  How can it be a HERBIVORE and yet eat only one kind
of plant?


> or BETA's form:
> 
>   MONOCULTUREFARM
> 	(#   ANIMALT :< HERBIVORE
>  	     attr livestock : @list (# eleT::ANIMALT #);
>  	     attr foodstock : @list (# eleT::ANIMALT.FOODT #); 
> 	#)

It's not especially readable, is it?
Is it really ":<" rather than Cluster's "<:"?  Very funny contrarianism!
Since "ANIMALT :< HERBIVORE" is inside the "(#" & "#)" enclosure I wouldn't
guess you could create a MONOCULTUREFARM(COW).

Since there's no "class" in front of "MONOCULTUREFARM" I'd guess that
everything in BETA is a class or pattern or somethin', huh?  So, by
having only one "form" it can be understood what this is.  Is there
any special notation to differentiate a main program from these others?

Do any of these MONOCULTUREFARMs (Sather, Cluster or BETA) inherit
from FARM or are they the lowest base of farm that will exist in this
class hierarchy?

[snipped a bunch]
 
> It might be difficult to argue which way is better for a farm, but as I
> said, the language should at least give the way that the speaker wants.

Yes, the language should provide a way to express something.  That's why
I cringe when I see syntax like BETA's.  :-)

How about...

  class MonocultureFarm ( food is plant, animal is herbivore ) is
    procedure feed ();
  end MonocultureFarm;

  class MonocultureFarm body is
    import list;
    object livestock is list(animal);
           foodstock is list(food);
    procedure feed ( get livestock is in out list(animal);
                     get foodstock is in out list(food)   ) is
    begin
      ...
    end feed;
  end MonocultureFarm;

  program temp is
    import MonocultureFarm;
    object myfarm is MonocultureFarm(corn,hog);
  begin
    myfarm.feed();
  end temp.

Since it's not like a procedure within a module the parameters of
MonocultureFarm which are of type/class plant and herbivore aren't
"import"ed first.  That's a little awkward, but these other languages
(BETA, Cluster, Sather) don't seem to need the "import".  Is it no
longer regarded as necessary?


> Back to the major differece:
>
>   Cluster's generic class are real classes but Sather's is not.
>   Therefore, by Cluster, HERBIVORE[GRASS] is a subclass/subtype
>   of HERBIVORE.

I hesitate to ask what kind of GRASS is an HERBIVORE.

>   By Sather, HERBIVORE[GRASS] cannot be a subclass/subtype of HERBIVORE.
>   That's whay Sather cannot have the expression:
> 
> 	ANIMALT < $HERBIVORE
> 
> because HERBIVORE is not a class.

I asked (above) if Sather would also have to use an "include HERBIVORE" to
comlete the equation.  This comparison of Cluster's inheritance scheme to
Sather's asks the same question.

If you're inheriting an HERBIVORE then how can it be an HERBIVORE that
only eats GRASS?  It seems to me that the tying together of the specific
food(s) to the animal has to be done at a higher level of abstraction --
probably in the algorithm which represents the farmer's actions.

You can put a COW in a field of several plants, but you can't force it
to eat only GRASS.  A HERBIVORE COW might choose to eat clover.  :-)
 

Mark S. Hathaway       <hathawa2@marshall.edu>


======================================================================= 42 ===
Date:    9 Jan 95 02:10:43 EDT
From:    hathawa2@marshall.edu (Mark S. Hathaway)
Subject: Re: Cows, Hogs & Farms

> In article <1995Jan4.191910.13968@schbbs.mot.com>,
> shang@corp.mot.com (David L. Shang) writes:

>> In article <1995Jan3.223031@hobbit>
>> hathawa2@marshall.edu (Mark S. Hathaway) wrote:

[ much deleted here and there throughout this post ]

> In reality, we always have exceptions. We can use covariance to rule out a  
> general principle and use run-time type check for a few exceptions. As to
> the animal example, it is clearly worthwhile to divide animals into
> herbivires, carnivores and (?)(animals eating both food) according to the
> type of their food. We can use covaraince. But it might be very hard to
> rule out a general principle for the futher classification for a certain
> number of animals.  

It's herbivore, carnivore & omnivore.
Eats plants,    meat      & pizza with everything!   :-)

 
> We are not developing a commercial software for zoologists, are we? These
> are only padagogical examples. Be wise to make things as simple as possible
> -- just for the key points you want to say. 

I have created a few examples in the past which thoroughly confused people
because they weren't realistic enough.  I'm trying to avoid the sins of
my past.

>>> class field [FoodType <: plant]
>>>    function getCrop(): FoodType;
>>> end field;
 
>> Isn't a generic field which can grow any plant more correct?  Doesn't the
>> notation you've given tie one specific plant to the field and not allow for
>> future crop rotations?  Farmers plant different crops to avoid depleting
>> the soil too much.
 
> This is an abstract field. No object can be intantiated by the class
> unless you associate it with a plant type.

Yes, but after you've instantiated an object with a particular plant, can
you then change the plant?

  
>>> class farm [AnimalType <: herbivore] is
>>>   animals: list [MemberType = AnimalType];
>>>   fields:  list [MemberType = field [FoodType = AnimalType.FoodType]];
>>>   function getRipeFood(): AnimalType.FoodType;
>>> 	   -- get the ripe food from one of its fields.
>>>   ...
>>> end farm;
>>> 
>    class hog_farm is farm [AnimalType = hog];
>    class cow_farm is farm [AnimalType = cow];

> Note that the generic classes I presented above are not conventional generic 
 
> classes. You cannot have this by Eiffel's generic class, which is not a real 
 
> class, and hence it is meaningless to discuss the subclass relationship
> between a generic class and the class instantiated by the generic class.

I like the looks of class farm above.  It's quite similar to what I've been
developing in pseudo-code.  I've used "(param)" instead of "[param]" though.

I'd certainly be interested to read further discussion on the differences
between these classes and those of Sather & Eiffel.  There seem to be some
rather major differences.

BTW, are these examples of yours in Cluster?


>>> program farming is
>>>          c is cow_farm;
>>>          h is hog_farm;
>>> begin
>>>   ...
>>>   for each animal in c.animals do animal.eat(aCorn); -- wrong!
>>>   for each animal in c.animals do animal.eat(aGrass); -- correct.
>>>   for each animal in c.animals do animal.eat (c.getRipeFood ()); 
>>>  						-- correct.
>>> end farming.

 
>>> Secondly, you could have an ill-structured heterogeneous farm where
>>> various type of herbivores are raised at random fields. That is, there
>>> is no relationship between a field type and a herbivore type:
>>> 
>>> class farm is
>>>   animals: list [MemberType <: herbivore];
>>>   fields:  list [MemberType <: field];
>>>   function getRipeFood(): plant;
>>> 	   -- get the ripe food from one of its fields.
>>> end farm;
 
>> Why do you say "animals: list [MemberType <: herbivore];"
>> instead of      animals: list [ herbivore ];
 
> The latter is equivalent to:
> 
> 	animals: list [ MemberType = herbivore ];
> 
> where "animals" is not a polymorphic (heterogeneous) variable.

Are you saying that without "<:" it won't recognize "herbivore" as a class
from which to inherit; and that in the second case it would simply "think"
"animals: list [ herbivore ];" refers to some "herbivore" other than the
class?

 
>>> procedure self_farming is (f is in farm)
>>> begin
>>>   ...
>>>   for each animal in f.animals do animal.eat(f.getRipeFood ()); -- wrong!
>>>   for each animal in f.animals do 
>>> 	plant food := f.getRipeFood();
>>> 	when typeof(animal).Foodtype = typeof(food) do
>>> 	     animal.eat(food); -- correct
>>>   end
>>> end self_farming.

Looks decent.  But, it doesn't make me want to take up farming.  :-)


Mark S. Hathaway       <hathawa2@marshall.edu>


======================================================================= 43 ===
Date:    Mon, 09 Jan 95 10:32:53 -0800
From:    heydon@pa.dec.com
Subject: Re: Question on generics

In a previous message <9501062053.AA19195@spieler.pa.dec.com>, I wrote:

> The generic Sequence interfaces and implementations live in the
> package named "sequence":

In separate e-mail, Farshad Nayeri pointed out to me that "sequence"
does not have its own separate package in the public distribution.
Instead, it lives in the "src/sequence" directory of the "libm3"
package.

Alternatively, the "Sequence.i3", "SequenceRep.i3", and "Sequence.m3"
files are available on the Modula-3 WWW server that Bill has set up.
The URL for the server's home page is:

  http://www.research.digital.com/SRC/modula-3/html/home.html

The URL for the alphabetical index for Modula-3 sources is:

  http://www.research.digital.com/SRC/m3sources/html/INDEX.html

The "Sequence" and "SequenceRep" generic interfaces, as well as the
"Sequence" generic module, are all reachable from this index.

- Allan

--------------------------------------------------------------------
Allan Heydon                           Digital Equipment Corporation
heydon@pa.dec.com                      Systems Research Center
(415) 853-2142                         130 Lytton Avenue
(415) 853-2104 (FAX)                   Palo Alto, CA 94301


======================================================================= 44 ===
Date:    9 Jan 1995 15:21:56 GMT
From:    jacobse@daimi.aau.dk (Jacob Seligmann)
Subject: Re: Cows, Hogs & Farms

Mark S. Hathaway <hathawa2@marshall.edu> wrote:

> > or BETA's form:
> > 
> >   MONOCULTUREFARM
> >     (#   ANIMALT :< HERBIVORE
> >          attr livestock : @list (# eleT::ANIMALT #);
> >          attr foodstock : @list (# eleT::ANIMALT.FOODT #); 
> >     #)
> 
> [...]
> 
> Since "ANIMALT :< HERBIVORE" is inside the "(#" & "#)" enclosure I wouldn't
> guess you could create a MONOCULTUREFARM(COW).

But you can! In BETA, you would say

   MONOCULTUREFARM (# ANIMALT :: COW #)

to denote a subclass of MONOCULTUREFARM in which the virtual attribute
ANIMALT is further-bound to COW. That is, genericity is handled through
inheritance and virtuals alone - there is no special template mechanism
whatsoever!

Of course, this is only possible because BETA allows virtual types, not
just virtual methods. This is typical of how BETA offers only a few
basic mechanisms, but makes them powerful and orthogonal, so that they
can be combined to obtain a wide range of features for which most other
languages provide special mechanisms.

> It's not especially readable, is it?
> [...]
> Yes, the language should provide a way to express something.  That's why
> I cringe when I see syntax like BETA's.  :-)

The reverse sign of the minimalism coin, of course, is the need to use
more syntax to express a feature which is obtainable through a special
(nice-looking) construct in another language.

I agree that 

   MONOCULTUREFARM [COW] 

or even 

   MONOCULTUREFARM [ ANIMALT = COW ]

is easier to read than

   MONOCULTUREFARM (# ANIMALT :: COW #) 

However, when working with BETA, you quickly learn to recognize use
patterns such as the one above. It's not a big deal in practice, really.

Best regards,

/Jacob Seligmann
------------------------------------------------------------------------
Computer Science Department            Phone:  +45 89 42 31 88
Aarhus University                      Direct: +45 89 42 32 74
Ny Munkegade 116                       Fax:    +45 89 42 32 55
DK-8000 Aarhus C, Denmark              E-mail: jacobse@daimi.aau.dk
------------------------------------------------------------------------
More info on BETA is available at URL http://www.daimi.aau.dk/~beta/info
------------------------------------------------------------------------


======================================================================= 45 ===
Date:    09 Jan 1995 18:40:58 GMT
From:    jackg@downhaul.crc.ricoh.com (Jack Greenbaum)
Subject: Circular imports


M3 does not allow interfaces to cicularly import each other. This comes
up when I'm trying to do the following:

A graph contains Node and Edge objects. These are distinct object
types. I would like the Node objects to contain fields of type Edge,
and the Edge object to contain fields of type Node so that the graph
is easily traversable. In order to do this the Node interface must
import the Edge interface so that an edge may be added to the node. As
well the Edge interface must import Node so that a node may be added
to an edge. Ooops! We're hosed. 

One way to solve this is to have a Graph interface which exports both
Edge and Node. Everyone is in the same interface, so no problem.

Is another way to do this to have multiple interfaces to Node, where one
of those interfaces is imported by Edge and doesn't make reference to
Edge? Then a single module will reveal the "One True Node" and export
all interfaces.

Does "System Programming with Modula-3" discuss such issues?
--
Jack Greenbaum -- Research Engineer, Ricoh California Research Center
---------------------------------------------------------------------
Digital: jackg@crc.ricoh.com   |  http://www.crc.ricoh.com/~jackg
---------------------------------------------------------------------
Analog:  (415) 496-5711 voice  |  2882 Sand Hill Rd. Suite 115
         (415) 854-8740 fax    |  Menlo Park, CA 94025-7002
---------------------------------------------------------------------


-- 
Jack Greenbaum -- Research Engineer, Ricoh California Research Center
---------------------------------------------------------------------
Digital: jackg@crc.ricoh.com   |  http://www.crc.ricoh.com/~jackg
---------------------------------------------------------------------


======================================================================= 46 ===
Date:    9 Jan 1995 15:25:59 GMT
From:    olevi@daimi.aau.dk (Ole Villumsen)
Subject: Beta syntax (was Re: Cows, Hogs & Farms)

In Danish schools, we learn that multiplication is denoted by a dot
(or nothing at all: xy means x times y), and a colon : is used
for division. When I started learning programming, I learned that * 
meant multiplication, and / was used for division. It's no problem: 
I got accustomed to * and / very quickly and never gave it a 
second's thought.

It's the same with Beta: A few things that are used often have a short 
notation in Beta that every programmer uses without thinking about it; 
but they (and especially the sum of them) are apt to confuse people 
who don't know Beta. For instance (from David L. Shang
<shang@corp.mot.com>'s posting):

>> or BETA's form:
>> 
>>   MONOCULTUREFARM
>>      (#   ANIMALT :< HERBIVORE
>>           attr livestock : @list (# eleT::ANIMALT #);
>>           attr foodstock : @list (# eleT::ANIMALT.FOODT #); 
>>      #)

The "attr" in the above should be deleted. The "@" later in the 
same lines do the job; which is very convenient once you know it. 
That's Beta. I'll return to "@" below. (Also, there should be a colon :
after MONOCULTUREFARM - it wasn't important, as the original posting 
didn't discuss syntax details; but we do now.)

Mark S. Hathaway <hathawa2@marshall.edu> asks:
 
>It's not especially readable, is it?

Most people dislike Beta's syntax at first. As a more experienced user
I'd say, it's very straightforward to read once you've learned it.
But beautiful - it's not.

>Is it really ":<" rather than Cluster's "<:"?  Very funny contrarianism!
>Since "ANIMALT :< HERBIVORE" is inside the "(#" & "#)" enclosure I wouldn't
>guess you could create a MONOCULTUREFARM(COW).

In Beta, you create a MONOCULTUREFARM(# animalT::cow #)
I suppose it's the same, only with a different syntax.
Just like you create a list (# eleT::ANIMALT #) instead of a list(animalT).
("List" alone would be a list that could contain any type of objects.)

Not knowing Cluster, I don't think Beta's ":<" and Cluster's "<:" have 
exactly the same meaning. Maybe it's a pure coincidence that the two 
languages include symbols made up of the same 2 characters. Beta uses

       x :   ...  for an ordinary (static) declaration
       x :<  ...  for a virtual declaration
       x ::< ...  for a further binding (extension) of a virtual
       x ::  ...  for a final binding (after which x is no longer virtual)

It's easy and consistent, isn't it?

>Since there's no "class" in front of "MONOCULTUREFARM" I'd guess that
>everything in BETA is a class or pattern or somethin', huh?  So, by
>having only one "form" it can be understood what this is. ...

Again, you have to know the language - but you'll learn very quickly,
since these are the details the Beta programmer uses every day and soon
stops thinking about:

        x: (# ... #); (* declares a pattern (e.g. a class) *)
        x: @ ... ;    (* declares a static instance (object) *)
        x: ^ ... ;    (* declares a dynamic reference to an instance *)

> ... Is there
>any special notation to differentiate a main program from these others?

The main program is preceeded by "--- program: descriptor ---"
(which is strictly speaking part of the fragment language, not
part of Beta itself).

>Yes, the language should provide a way to express something.  That's why
>I cringe when I see syntax like BETA's.  :-)

You won't find a programming langauge with greater expressive power 
than Beta :-) :-)

>Since it's not like a procedure within a module the parameters of
>MonocultureFarm which are of type/class plant and herbivore aren't
>"import"ed first.  That's a little awkward, but these other languages
>(BETA, Cluster, Sather) don't seem to need the "import".  Is it no
>longer regarded as necessary?

If plant and herbivore are defined in different files (fragment 
groups), you should do an "include" of those files. Again, this is done 
using the fragment language.

If you have other Beta questions, please ask. You can also read more 
in the Beta FAQ file.

I have set follow-ups to comp.lang.beta.

Ole
--
Ole Villumsen, Computer Science Department, Aarhus University, Denmark

A European Union is a self contradiction.
Either the European will kill the union, or the union will kill the European.


======================================================================= 47 ===
Date:    Mon, 9 Jan 1995 18:36:27 GMT
From:    shang@corp.mot.com (David L. Shang)
Subject: Re: Cows, Hogs & Farms

In article <3eknd9$noi@network.ucsd.edu> mbk@inls1.ucsd.edu (Matt Kennel)  
writes:
> Ok you could do this in Sather by just saying
> 
> illinois: MONOCULTUREFARM{GRASS,$HERBIVORE{GRASS}}
> 
> and so the animals in 'illinois' would be anything that could eat grass.

This is my Cluster's version in (2), which I used to describe an euivalent form
  
to the Sather's orignal version. Now you translate it back into Sather.

To use MONOCULTUREFARM in version (2),  Cluster has the equivalent form:

illinois: MONOCULTUREFARM[GRASS,HERBIVORE[GRASS]]

where illinois could be a farm with cows, sheeps, and any other creatures that 
 
are subclasses of HERBIVORE[GRASS], or,

illinois: MONOCULTUREFARM[GRASS,COW]

where illinois is a cow farm if we suppose that COW be a subclass of  
HERBIVORE[GRASS].

In Cluster's version (1), you can simply written:

illinois: MONOCULTUREFARM[HERBIVORE[GRASS]], or
illinois: MONOCULTUREFARM[COW]

In Cluster's version (3), you can simply written:

illinois: MONOCULTUREFARM[GRASS]

> : ... by Cluster, HERBIVORE[GRASS] is a subclass/subtype  
> : of HERBIVORE. By Sather, HERBIVORE[GRASS] cannot be a subclass/subtype of  
> : HERBIVORE. That's whay Sather cannot have the expression:
> 
> : 	ANIMALT < $HERBIVORE
> 
> : because HERBIVORE is not a class.
> 
> OK.  But you could write a type $HERBIVORE > $HERBIVORE{FOODT} that
> specified just those features not dependent on FOODT (say
> "eat_or_barf(x:$PLANT)"), and so all COW's and HOG's could be a subclass of
> some $HERBIVORE, if somewhere else you needed to classify ANIMAL's on the
> basis on whether or not they were an $HEBIVORE.
> 

Is it a little bit strange to have a hieratchy like:

	$HERBIVORE > $HERBIVORE{FOODT} > COW

? Is HERBIVORE{FOODT} or HERBIVORE{GRASS} a real class by Sather? If they are  
not, what is the relationship between:

	HERBIVORE > HERBIVORE{FOODT}

and

	HERBIVORE{FOODT} > COW

? The only valid relationship I see is:

	HERBIVORE > COW

HERBIVORE dose not have any information on the food type. If we try to classify
  
herbivores accroding to their food types, this HERBIVORE class could not help  
more than what we have like this:

	ANY_OBJECT > COW

> 
> All type parameters must be resolved at compile time;
> there must be some performance benefit, yes?

Not necessarily true. Class paprameters can be resovled at run time by Cluster.
  
This is done by dynamic binding. I don't see any significant performance  
slowing down by just an indirect access when a dynamic binding must be  
performed. The benefit is the power of dynamic typing. For example:

	farm: MONOCULTUREFARM; // a polymorphic farm variable;
	creature: HERBIVORE; // a polymorphic herbivore animal varaible;
	...

	creature := aMixedmarket.GetHerbivoreFromMixedMarket();
		// at this point, we do not know the exact type of
		// the creature.
	...
	farm := new MONOCULTUREFARM[typeof(creature)];
		// create a farm in a new class accroding to
		// the type of the creature
	when typeof(farm).ANIMALT is typeof(creature) do
		farm.add(creature);

The last type assurance statement is used for type-safety, because 

	creature -> farm.add's input

is a cross assignment, which, like a reverse assignment, violates the  
substitution law. The compiler won't let the program pass if the type assurance
  
statement is not used.

However, the type assurance statement may not necessary accroding to the  
context. It could be eliminated by optimization. It is the same case as:

	var i: integer := 4;
	if i=4 then i++;

Therefore, all the programs passed by the compiler will be type safe. No system
  
level type check or data flow analysis is required for type safety. They are  
required only for the purpose of code optimization.


David Shang




======================================================================= 48 ===
Date:    Mon, 9 Jan 1995 20:35:28 GMT
From:    shang@corp.mot.com (David L. Shang)
Subject: Re: Cows, Hogs & Farms

In article <1995Jan9.005627@hobbit>  writes:
> > In article <1995Jan6.164948.4782@schbbs.mot.com>,
> > shang@corp.mot.com (David L. Shang) writes:
> > This form is slightly different in semantics from the Cluster's form:
> > 
> >   class MONOCULTUREFARM  [ANIMALT <: HERBIVORE]
> >  	attr livestock : list[ANIMALT];
> >  	attr foodstock : list[ANIMALT.FOODT]; 
> > 							----- (1)
> 
> Does Cluster separate the subtyping and inheritance as Sather does?
> 

No. Subtype and subclass are the samething by Cluster.

> Is the use of "ANIMALT <: HERBIVORE" a convenience or requirement?

For a MONOCULTUREFARM classified by the type herbivore animals, using a class  
parameter "ANIMALT <: HERBIVORE" is a requirement, otherwise, a MONOCULTUREFARM
  
will be a heterogenrous farm.

> 
> So, ANIMALT.FOODT implies that a particular food is associated with a
> particular animal?  How can it be a HERBIVORE and yet eat only one kind
> of plant?

It cannot be in reality. I am reluctant to complicate this example.  But to  
describe a HERBIVORE that eat more than one kinds of food is also possible by  
multiple inheritance:

	class COW is HERBIVORE [ FOODT = GRASS ],
		     HERBIVORE [ FOODT = HAY ],
		     ...

But there will be a problem when you try to substitude ANIMALT with COW:

	class MONOCULTUREFARM  [ANIMALT <: HERBIVORE]
	      attr livestock : list[ANIMALT];
	      attr foodstock : list[ANIMALT.FOODT];
 
	cow_farm: MONOCULTUREFARM [COW];

As COW has multiple bases:  HERBIVORE[GRASS], HERBIVORE[HAY], ..., which base  
is used? You have to specify:

	grass_farm: MONOCULTUREFARM [COW as HERBIVORE[GRASS]];

or
	hay_farm: MONOCULTUREFARM [COW as HERBIVORE[HAY]];

In fact, the MONOCULTUREFARM designed here is no longer suitable for an animal 
 
that eats more than one plant, becase it only keeps one kind of food. However, 
 
if we could figure out a subclass of PLANT for COW, say, COW_FOOD, ther is not 
 
problem to have HERBIVORE[COW_FOOD] and the MONOCULTUREFARM as define above.

Unfortuantely, in most cases, it is almost impossible to classify herbivores  
according to the food type they eat. This is probably a bad example to  
demonstrate the covariance. I whould like to use the herbivore/carnivore  
classification example.

> 
> Do any of these MONOCULTUREFARMs (Sather, Cluster or BETA) inherit
> from FARM or are they the lowest base of farm that will exist in this
> class hierarchy?
> 

By Cluster, I guess BETA too, MONOCULTUREFARM[ANIMAT<:HERBIVORE] could be the  
lowest base of farm that exist in the class hierarchy. but no Sather, since a  
generci class is not a real class by Sather.

We can have this hierarchy:

		(1)MONOCULTURE[ANIMAT<:HERBIVORE]

    (2)MONOCULTURE[ANIMAT<:HERBIVORE]       (3)MONOCULTURE[HERBIVORE[PLANT]]

 (4)MONOCULTURE[COW]  (5)MONOCULTURE[HOG]


Note that ANIMAT is fixed to HERBIVORE[PLANT] in (3). It is a MONOCULTURE farm 
 
if we don't care the further division of the herbivores according to their  
animal food types. But we may still have an interest in the further division  
according to other things by adding addtional class parameters in subclasses.

> How about...
> 
>   class MonocultureFarm ( food is plant, animal is herbivore ) is
>     procedure feed ();
>   end MonocultureFarm;
> 
>   class MonocultureFarm body is
>     import list;
>     object livestock is list(animal);
>            foodstock is list(food);
>     procedure feed ( get livestock is in out list(animal);
>                      get foodstock is in out list(food)   ) is

Why should you provide additional input/output parameters for feed in the class
  
body? Why should the feed interfaces be different?

>     begin
>       ...
>     end feed;
>   end MonocultureFarm;
> 
>   program temp is
>     import MonocultureFarm;
>     object myfarm is MonocultureFarm(corn,hog);

How about:

	object myfarm is MonocultureFarm(corn,cow);

if a cow dose not eat corn?
	
>   begin
>     myfarm.feed();
>   end temp.
> 
> Since it's not like a procedure within a module the parameters of
> MonocultureFarm which are of type/class plant and herbivore aren't
> "import"ed first.  That's a little awkward, but these other languages
> (BETA, Cluster, Sather) don't seem to need the "import".  Is it no
> longer regarded as necessary?
> 

"import", or "use" decalrations is not the subject we discussed here. BETA and 
 
Cluster do need these declarations to have a complete program.

> 
> If you're inheriting an HERBIVORE then how can it be an HERBIVORE that
> only eats GRASS?  

Why not? Of cuase if you define a HERBIVORE that can eat ANY plant, a HERBIVORE
  
that only eats GRASS cannot be a subclass. But if we define a HERBIVORE that  
can eat a certain type of food which is a subclass of PLANT, why cannot a  
HERBIVORE that only eats GRASS be a subclass?

> 
> You can put a COW in a field of several plants, but you can't force it
> to eat only GRASS.  A HERBIVORE COW might choose to eat clover. 

Agian, I don't consider this herbivore example a good example to demonstrate  
covariance. Lets just take the assumption that COW eat GRASS only and HOG eat  
CORN only, and make things simple. If you don't like the assumption, we may  
consider the animal/herbivore/carnivore example.

David Shang





======================================================================= 49 ===
Date:    9 Jan 95 08:33:40
From:    dagenais@notung.vlsi.polymtl.ca (Michel Dagenais)
Subject: Re: How to install M3?


   I just got the src files for M3 compiler, lib, etc., for Linux 
   from sunsite FTP site. (src-m3-3.3l2.strip.tar.gz, m3gdb.tgz and 
   *.lsm and *.html files). After uncompressed the files, I found
   out that there are pre-compiled binaries, src files and lib files. 
   BUT there is no instruction how to install the packages (setup 
   the path and env variables, etc.).  Is it enough just by setting 
   binaries file path? 

These files originate from ftp.vlsi.polymtl.ca:pub/m3/linux. There you
will find a README. Basically you need to set your PATH variable
to point to /usr/local/soft/modula3-3.3/bin and your LD_LIBRARY_PATH
to /usr/local/soft/modula3-3.3/lib/m3/LINUX.
--

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



======================================================================= 50 ===
Date:    10 Jan 1995 07:29:47 GMT
From:    bhawley@orion.it.luc.edu (Brian Hawley)
Subject: Re: Circular imports

Jack Greenbaum (jackg@downhaul.crc.ricoh.com) wrote:

: M3 does not allow interfaces to cicularly import each other. This comes
: up when I'm trying to do the following:

: A graph contains Node and Edge objects. These are distinct object
: types. I would like the Node objects to contain fields of type Edge,
: and the Edge object to contain fields of type Node so that the graph
: is easily traversable. In order to do this the Node interface must
: import the Edge interface so that an edge may be added to the node. As
: well the Edge interface must import Node so that a node may be added
: to an edge. Ooops! We're hosed. 

: One way to solve this is to have a Graph interface which exports both
: Edge and Node. Everyone is in the same interface, so no problem.

: Is another way to do this to have multiple interfaces to Node, where one
: of those interfaces is imported by Edge and doesn't make reference to
: Edge? Then a single module will reveal the "One True Node" and export
: all interfaces.

Why can't you just define a module Graph, which contains types Node and 
Edge? If you can't define more than one object type in a module, doesn't 
that get rid of a major advantage that Modula-3 has over Eiffel and C++, 
the module scope of visibility rather than class scope? 

I thought that the whole advantage of a seperate module scope in oop was 
to enable cooperative classes like your Node-Edge to work without needing 
friend classes or circular interfaces. Since I program mostly in Oberon-2 
I am not aware of the special limitations of Modula-3, but this kind of 
restriction would greatly increase the amount of code I would have to 
write and would complicate the public interfaces (i.e. those visible to 
others than the partner).

An example of cooperative object types is the Oberon file i/o. There is a 
module Files, which exports types File and Rider. File represents the 
array of bytes on the disk, and Rider represents an access point to a 
File. There can be many Riders on a File, at different positions, but 
a Rider only points to one File. The i/o is buffered, using a third type 
Buffer that is not exported. A File can have multiple buffers, but only 
one Buffer to a (disk) block. Each Rider is associated with a Buffer, but 
if more than one Rider is in the same block, they use the same Buffer.

In this example, Buffer has to be visible to Rider and File, but should 
not be public. If you define one object type to a module, Buffer will be 
public (will have at least one public interface). This is the problem 
with traditional oop languages like smalltalk and C++. It should not be a 
problem with languages like Modula-3 and Oberon-2. Just my $.02.

Brian Hawley
bhawley@orion.it.luc.edu and math.luc.edu


======================================================================= 51 ===
Date:    9 Jan 95 08:38:33
From:    dagenais@notung.vlsi.polymtl.ca (Michel Dagenais)
Subject: Re: SRC M3 v. 3.4 out


   A few of us have been testing the system to check for minor problems
   before it goes "public". I am happy to report that everything has been
   very smooth on SPARCs.  (As Bill says, however, please wait until he
   announces it, as some of the minor changes haven't made it back to the
   release.)

The whole source tree is available under ftp.vlsi.polymtl.ca
pub/lude/modula3-3.4 in src/orig with locally modified files
in src/poly and binaries under run/poly/sun4.1_sparc. I have
problems with Mentor and Obliq which i did not have time to
investigate yet. This is why i would recommend that you let
the dust settle for a week or so.

   I'd like to take this chance to commend Bill Kalsow and the rest of
   the people at SRC who helped with the SRC Modula-3 distribution for
   doing such a great job!

Indeed! Very much so!!
--

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



======================================================================= 52 ===
Date:    10 Jan 1995 16:59:40 GMT
From:    kalsow@src.dec.com (Bill Kalsow)
Subject: Re: Circular imports

In article <JACKG.95Jan9104058@downhaul.crc.ricoh.com>, jackg@downhaul.crc.rico
h.com (Jack Greenbaum) writes:
>
> M3 does not allow interfaces to cicularly import each other. This comes
> up when I'm trying to do the following:
> 
> A graph contains Node and Edge objects. These are distinct object
> types. I would like the Node objects to contain fields of type Edge,
> and the Edge object to contain fields of type Node so that the graph
> is easily traversable. In order to do this the Node interface must
> import the Edge interface so that an edge may be added to the node. As
> well the Edge interface must import Node so that a node may be added
> to an edge. Ooops! We're hosed. 

My usual solution is to define the interrelated types as opaques
in a tiny interface.  Then, introduce the names I prefer in higher-level
interfaces and use them whenever possible.  For example:

   INTERFACE XX;
   TYPE Node  <: REFANY; (* == Node.T *)
   TYPE Edge  <: REFANY; (* == Edge.T *)
   END XX.

   INTERFACE Node;
   IMPORT XX;
   TYPE T = XX.Node;
   PROCEDURE New (READONLY edges: ARRAY OF XX.Edge): T;
   ...

   INTERFACE Edge;
   IMPORT XX;
   TYPE T = XX.Edge;
   PROCEDURE New (a, b: XX.Node): T;
   ...

As in the example, I usually break the circularity symmetrically.
It's possible to define only one of XX.Node or XX.Edge and only
define the ".T" version of the other.  In my experience, this
arrangement usually decays over time and becomes hard to understand.

If you need, you can provide more information in the Node and Edge
interfaces by including full or partial revelations.  For example:

   INTERFACE Edge;
   IMPORT XX;
   TYPE T = XX.Edge;
   REVEAL T <: OBJECT a, b: XX.Node; END;
   PROCEDURE New (a, b: XX.Node): T;
   ...

Finally, all of the implementation code and any higher-level
interfaces use the names Node.T and Edge.T.  For example:

   INTERFACE Graph;
   IMPORT Node, Edge;
   TYPE T <: REFANY;
   PROCEDURE FromNodes (READONLY n: ARRAY OF Node.T): T;
   PROCEDURE FromEdges (READONLY e: ARRAY OF Edge.T): T;

Anyway, that's what I do.

  - Bill Kalsow




======================================================================= 53 ===
Date:    9 Jan 95 08:43:05
From:    dagenais@notung.vlsi.polymtl.ca (Michel Dagenais)
Subject: Postscript for the M3 language definition


In http://www.vlsi.polymtl.ca/m3/Doc you will find the Postscript for a
number of Modula-3 related documents including the language definition.
It was derived automatically from the HTML version available on the
Web; any formatting error you may find there is probably mine since
the tools used for this conversion still have limitations.
--

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



======================================================================= 54 ===
Date:    Tue, 10 Jan 95 18:02:33 GMT
From:    lady0065@sable.ox.ac.uk (David J Hopwood)
Subject: Re: Cows, Hogs & Farms

In article <1995Jan5.183534.10065@schbbs.mot.com>,
David L. Shang <shang@corp.mot.com> wrote:
>In article <3e07c4$sup@muss.cis.McMaster.CA> u9442202@muss.cis.McMaster.CA  
>(E.H. Schnetter) writes:
>> OK, here is an example in Sather.

[example using type-cases snipped]

>What you presented here is "Invaraince + Runtime Type Check", not a
>covariance.
>
>At a hogsty, if there is a plate saying "please feed me any plant", what will
>happen? The sty will be full of rotten food that the hog does not eat.
>
>The plate should say "please feed me corn only". That is, the eat interface  
>should tell its feeder the right food (if we suppose that a hog eat corn
>only).
>
>I'm not syaing that an interface should always tells the exact type. It
>depends on the desired semantics for that function.
>
>"eat" definitely needs an exact interface:
>
>	hog eats corns only  -- covariance
>
>"try" may have a vaguer interface:
>
>	hog try all plant  -- invaraince + runtime type check
>
>As I always said, a good language should provide all the possiblities.

Exactly. In the general case, we have an Animal which is guaranteed to eat all
food of type A, and may in addition eat food of type B:

type Animal {A, B}
    eat (A)         -- accept _at least all_ food of type A
    try (partial B) -- accept _at least some_ food of type B

A hog is guaranteed to eat all corn, and may in addition eat other plants:

type Hog
    eat (Corn)
    try (partial Plant)

Note that Hog is intended to be equivalent to Animal {Corn, Plant}; they
represent the same type.

The argument of try is declared to be partial, to indicate that it is not
necessarily defined for all Plants.

Suppose that a hog, fred, eats both corn and maize, but nothing else (and in
particular, not venus-flytraps):

venus-flytrap: Plant := ...
maize: Plant := ...
corn: Corn := ...
fred: Hog := ...

fred.try (venus-flytrap) -- legal, but fails at run-time
fred.try (maize)         -- legal, and succeeds at run-time
fred.try (corn)          -- legal, and succeeds at run-time

fred.eat (venus-flytrap) -- illegal (detected statically)
fred.eat (maize)         -- also illegal, since the semantics of eat requires
                         -- that success is guaranteed
fred.eat (corn)          -- legal, no run-time check required

try and eat have different semantics, in that they make different guarantees
about whether the call will succeed. Most languages do not allow try and eat
to be declared differently (ie. they have no equivalent to 'partial').

One reason for declaring them differently is as a warning to the programmer.
To use try properly, the program must be designed so that it does not matter
if it succeeds or not (as in David Shang's excellent example of type-safely
matching a heterogeneous list of animals with a list of foods).

Another reason is that they behave differently with respect to subtyping.
Ordinary parameters are contravariant, but partial parameters are not
necessarily so.
For example, is Animal {Corn, Maize} a subtype of Animal {Corn, Plant}?
It must be, since fred is evidently a member of type Animal {Corn, Maize},
and in the above example we declared fred to be of type Hog (ie.
Animal {Corn, Plant}). Ie. the argument of try (in this case) is covariant.

Consideration of similar examples shows that a programming language cannot
impose _either_ co- or contravariance on the types of partial arguments,
without rejecting some perfectly type-safe programs. It must allow these types
to be changed arbitrarily. Since the programmer is required to handle the case
where the method fails, this does not contravene type safety.

[much snipped]

>Run time type check can also be encapsulated by a hog's method, say "try":
>
>	function hog::try(food: plant): plant
>	enter
>		when typeof(food) is corn do 
                     ^^^^^^^^^^^^^^^^^^^^
>		{	eat (food);
>			return nil;
>		}
>		return food;
>	end;

try should allow the run-time type of its argument to be a subtype of corn.
It should not restrict it to being exactly corn. Ie. the language should allow
something like:

when typeof(food) is-subtype-of corn do ...

>Back to the original example when both the food type and the animal type are  
>unknown:

[example of type-safely matching a heterogeneous list of animals with their
corresponding foods snipped]

>From the above example, we can see that a  runtime type mismatch is not
>necessarily an exception, nor a type error. The system is designed this way.
>It is the desired semantics.
>
>What is a type error? A type error happens only when the type voilates the  
>requirement of the interface specification.
>
>	hog eats grass
>
>is a type error, but
>
>	hog tries grass
>
>is not a type error.
>
>Runtime type check is not an very important issue. The key point is
>whether the language can say the way you want!
>
>David Shang

Agreed.

David Hopwood
david.hopwood@lmh.oxford.ac.uk


======================================================================= 55 ===
Date:    10 Jan 95 21:16:07 EDT
From:    hathawa2@marshall.edu (Mark S. Hathaway)
Subject: Re: Cows, Hogs & Farms

> In article <1995Jan10.180233.23224@inca.comlab.ox.ac.uk>,
> lady0065@sable.ox.ac.uk (David J Hopwood) writes:

>> In article <1995Jan5.183534.10065@schbbs.mot.com>,
>> David L. Shang <shang@corp.mot.com> wrote:

>>> In article <3e07c4$sup@muss.cis.McMaster.CA>
>>> u9442202@muss.cis.McMaster.CA (E.H. Schnetter) writes:

>>> OK, here is an example in Sather.

> [example using type-cases snipped]

>>What you presented here is "Invaraince + Runtime Type Check", not a
>>covariance.
>>
>>At a hogsty, if there is a plate saying "please feed me any plant", what
>>will happen? The sty will be full of rotten food that the hog does not eat.
>>
>>The plate should say "please feed me corn only". That is, the eat interface  
>>should tell its feeder the right food (if we suppose that a hog eat corn
>>only).

Why should a plate say "please feed me corn only"?  Since when is that
relevant?  It's the HOG which favors CORN.

The hog is a herbivore which eats and favors corn.  A farmer (presumably)
feeds (read as offers) something (usually corn) to the hog.  You can say
the hog has a method eat(), but that doesn't explain the states which are
needed for it to decide when and what and how much to eat().  And, when
the hog sees something in its trough and it appears to be corn and the hog
is hungry (nearly always) the hog still might not eat if it senses there's
something contaminating the food.

Even the American congressman/woman won't feed at the gov't. trough if
it's not something his constituents want.  :-)

I favor the declaration of HOG separate from its foods.  There might be
a hog in some part of the world which doesn't eat corn.  Maybe the favorite
food of HOG will depend more upon what's available than we're imagining.
If a hog will eat something else then the class with CORN will be wrong.
A more generic HOG with a derived HOG_liking_CORN or a HOG with an attribute
( attr favorite_food is plant(corn) ) would be more enduring and correct.


> try and eat have different semantics, in that they make different guarantees
> about whether the call will succeed. Most languages do not allow try and eat
> to be declared differently (ie. they have no equivalent to 'partial').

Can't "try" be easily achieved with...

  procedure freds_life is
  begin
    if food_available AND hungry AND ( food = CORN ) then
      fred.eat(food);
    else
      #OUT.write "Yuck, get this " + string(food) + " outta here!" + nl;
    end;
  end freds_life;

I can't see HOG having a method TRY.  That makes no sense.


Mark S. Hathaway       <hathawa2@marshall.edu>


======================================================================= 56 ===
Date:    Thu, 12 Jan 95 03:15:15 GMT
From:    lady0065@sable.ox.ac.uk (David J Hopwood)
Subject: Re: Cows, Hogs & Farms

In article <1995Jan9.005627@hobbit>,
Mark S. Hathaway <hathawa2@marshall.edu> wrote:
>> In article <1995Jan6.164948.4782@schbbs.mot.com>,
>> shang@corp.mot.com (David L. Shang) writes:
...
>>> You can do most of Cluster's static solution in Sather, and I guess Eiffel.
>>> 
>>> ...
>>> class MONOCULTUREFARM{FOODT, ANIMALT < $HERBIVORE{FOODT} }  is
>>> 	attr livestock : LIST{ANIMALT};  -- type is known at compile time
>>> 	attr foodstock : LIST{FOODT};	 -- type is known 
>>> ...
>
>Should there be a $FOOD abstract type used here ( "FOODT < $FOOD" )?
Yes, that would be better.

>Would there have to be an "include HERBIVORE" and maybe "include FOOD"
>for this to work?
No. That would only be needed if we wanted to copy the implementation of the
classes HERBIVORE and FOOD, which is not the case here.

>> This form is slightly different in semantics from the Cluster's form:
>> 
>>   class MONOCULTUREFARM  [ANIMALT <: HERBIVORE]
>>  	attr livestock : list[ANIMALT];
>>  	attr foodstock : list[ANIMALT.FOODT]; 
>> 							----- (1)
>
>Does Cluster separate the subtyping and inheritance as Sather does?

No. In Cluster subclassing implies subtyping. IMO this is not a good idea,
because it is useful to be able to use part of the implementation of a class
without subtyping from it.

>Is the use of "ANIMALT <: HERBIVORE" a convenience or requirement?

It is a requirement if you want to make ANIMALT a polymorphic type variable
that can be referred to within MONOCULTUREFARM.
(ANIMALT on its own would mean ANIMALT <: ANY, which is wrong in this case).

>So, ANIMALT.FOODT implies that a particular food is associated with a
>particular animal?
Yes (more accurately, a particular type of food with a particular type of
animal).

>How can it be a HERBIVORE and yet eat only one kind
>of plant?
If ANIMALT is bound to exactly HERBIVORE, then the animals will eat any PLANT
(ie. HERBIVORE.FOODT = PLANT)
If it bound to a subtype of HERBIVORE, then they will eat a subtype of PLANT
(eg. HOG.FOODT = CORN)

>> or BETA's form:
>> 
>>   MONOCULTUREFARM
>> 	(#   ANIMALT :< HERBIVORE
>>  	     attr livestock : @list (# eleT::ANIMALT #);
>>  	     attr foodstock : @list (# eleT::ANIMALT.FOODT #); 
>> 	#)
>
>It's not especially readable, is it?
Nope :-)

>Is it really ":<" rather than Cluster's "<:"?  Very funny contrarianism!
Yep :-)

>Since "ANIMALT :< HERBIVORE" is inside the "(#" & "#)" enclosure I wouldn't
>guess you could create a MONOCULTUREFARM(COW).

Yes you can (but I can't remember the syntax).

>Since there's no "class" in front of "MONOCULTUREFARM" I'd guess that
>everything in BETA is a class or pattern or somethin', huh?
Yes (a pattern).

>So, by having only one "form" it can be understood what this is.  Is there
>any special notation to differentiate a main program from these others?
I don't know (I don't program much in BETA). The idea of a main program is only
really needed at the end of development, and only then because you're running
it from a non-OO environment.

>Do any of these MONOCULTUREFARMs (Sather, Cluster or BETA) inherit
>from FARM or are they the lowest base of farm that will exist in this
>class hierarchy?
It doesn't really matter. No other FARM types are being modelled in this
example, but they could be.

>[snipped a bunch]
> 
>> It might be difficult to argue which way is better for a farm, but as I
>> said, the language should at least give the way that the speaker wants.
>
>Yes, the language should provide a way to express something.  That's why
>I cringe when I see syntax like BETA's.  :-)

To be fair, orthogonality is very nice. But I think it could have been done
in a little more user-friendly way, in the case of BETA. All those symbols
give me a headache.

>How about...
>
>  class MonocultureFarm ( food is plant, animal is herbivore ) is
>    procedure feed ();
>  end MonocultureFarm;
>
>  class MonocultureFarm body is
>    import list;
>    object livestock is list(animal);
>           foodstock is list(food);
>    procedure feed ( get livestock is in out list(animal);
>                     get foodstock is in out list(food)   ) is
>    begin
>      ...
>    end feed;
>  end MonocultureFarm;
>
>  program temp is
>    import MonocultureFarm;
>    object myfarm is MonocultureFarm(corn,hog);
>  begin
>    myfarm.feed();
>  end temp.

Looks good to me. This sort of code would be valid in Cluster, Sather and
BETA.
The difference in Cluster et al, is that you can also say

  program temp is
    import MonocultureFarm;
    object myfarm is MonocultureFarm(myanimal, myfood);
    object currentanimal is myanimal;
    object currentfood is myfood;
  begin
    -- can refer to 'myanimal' and 'myfood' as type variables anywhere
    -- inside here.
  end temp.

>Since it's not like a procedure within a module the parameters of
>MonocultureFarm which are of type/class plant and herbivore aren't
>"import"ed first.  That's a little awkward, but these other languages
>(BETA, Cluster, Sather) don't seem to need the "import".  Is it no
>longer regarded as necessary?

Personally, I like explicitly importing things. It means you don't have
cluttered global namespaces. But it's not strictly necessary.

>> Back to the major difference:
>>
>>   Cluster's generic class are real classes but Sather's is not.
>>   Therefore, by Cluster, HERBIVORE[GRASS] is a subclass/subtype
>>   of HERBIVORE.
>
>I hesitate to ask what kind of GRASS is an HERBIVORE.

So you should. Personally, I find the way Cluster is being explained here
rather obscure; I would prefer to consider HERBIVORE to refer to a module
rather than a type (because it isn't qualified with a type parameter).

The thing which is causing the confusion is that Cluster allows type parameters
to be referred to either by name, or by position (a bit like function
parameters in Ada83, if that helps).

As far as I can make out, it also allows the following syntactic sugar:
instead of declaring

object foo is X [TYPETAG = T] -- where T is a type variable
object bar is T

you can say

object foo is X               -- the T is now implicit
object bar is X.TYPETAG

Using that sugar, you can claim that HERBIVORE [GRASS] (which is the same
thing as HERBIVORE [FOODT = GRASS]), is a subtype of HERBIVORE.
That is equivalent to introducing T as a local type variable, and saying that
HERBIVORE [GRASS] is a subtype of HERBIVORE [T] for some T.

I hope I haven't confused people utterly with that.

>>   By Sather, HERBIVORE[GRASS] cannot be a subclass/subtype of HERBIVORE.
>>   That's whay Sather cannot have the expression:
>> 
>> 	ANIMALT < $HERBIVORE
>> 
>> because HERBIVORE is not a class.
>
>I asked (above) if Sather would also have to use an "include HERBIVORE" to
>comlete the equation.  This comparison of Cluster's inheritance scheme to
>Sather's asks the same question.

The basic difference between Sather's genericity and Cluster's is that in
Cluster (and BETA, Cecil, Trellis/Owl, and lots of functional languages), you
can use type variables outside the particular class that defines them.

The difference between Sather's inheritance and Cluster's is a separate
issue; in Sather, subtyping is separated from inheritance (which is why you
need include as a new construct), while in Cluster it is not.

>If you're inheriting an HERBIVORE then how can it be an HERBIVORE that
>only eats GRASS?  It seems to me that the tying together of the specific
>food(s) to the animal has to be done at a higher level of abstraction --
>probably in the algorithm which represents the farmer's actions.

Exactly. To do this, you need to use type parameters within the farmer
algorithm, not just within MONOCULTUREFARM. The resulting algorithm doesn't
need to be instantiated with specific types in order to work correctly (as in
Sather, C++, Ada-style genericity); there is only one algorithm, which can be
used with its parameters bound either to type variables, or to specific types.

Cluster et al allow you to do this; Sather et al don't.

...
>Mark S. Hathaway       <hathawa2@marshall.edu>

David Hopwood
david.hopwood@lmh.oxford.ac.uk


======================================================================= 57 ===
Date:    Thu, 12 Jan 1995 14:20:08 GMT
From:    trumpet-user@a.site.name (Default Trumpet User)
Subject: Re: OOPSLA'95 Electronic Hotline

In article <D1LqH8.yE@cunews.carleton.ca> bnfb@scs.carleton.ca (Bjorn Freeman-B
enson) writes:
>From: bnfb@scs.carleton.ca (Bjorn Freeman-Benson)
>Subject: OOPSLA'95 Electronic Hotline
>Date: Fri, 30 Dec 1994 02:19:56 GMT

>            OOPSLA'95 ELECTRONIC INFORMATION HOTLINE

>              Tenth Annual ACM Conference on
>Object-Oriented Programming Systems, Languages and Applications
> 
>CONFERENCE CHAIR  REBECCA WIRFS-BROCK           15-19 October 1995
>PROGRAM CHAIR     MARY LOOMIS                   Austin, TX, USA

>________________ WHAT INFORMATION IS AVAILABLE ____________________

>The Hotline currently contains the on-line version of the Call for
>Participation including the submission dates, guidelines, articles about
>how to write good papers, important dates, etc.  As October approaches,
>more and more information will be available including the Advanced Program,
>registration forms, maps of Austin, etc.

>__________ HOW TO RECEIVE MORE INFORMATION ELECTRONICALLY _________

>There are three mechanisms for receiving further information electronically:
>WWW, anonymous ftp, and e-mail list server.  

>                            W W W

>http://info.acm.org/sig_forums/sigplan/oopsla/oopsla95.html


>                    A N O N Y M O U S   F T P

>Host name:     info.acm.org
>Host id:       137.117.5.4
>FTP directory: sig_forums/sigplan/oopsla/

>The file READ.ME contains a list of the files available.


>                E - M A I L   L I S T   S E R V E R

>        [Unfortunately, the ACM Email List Server is currently
>        not functioning...  I will repost this announcement when the
>        list server recovers.]


>____________________ CONTACT WITH A HUMAN ________________________

>This Hotline is automatic - your e-mail has been processed by auto-answer
>program.  No human has read your message.  If you are having trouble with
>the Hotline, or need to communicate with an OOPSLA'95 representative about
>some issue that the Hotline does not provide an answer for, you can contact
>bjorn@oti.on.ca (for Hotline Problems), oopsla95@applelink.apple.com
>(for OOPSLA'95 Administration).

>                        >>> PLEASE <<< 

>Please do not contact the administration or registration people if your
>problem can be answered by files on the Hotline.  OOPSLA is a big
>conference and it is staffed by unpaid volunteers - we give our time to
>make it happen.  This Hotline has been set up to provide answers to
>Frequently Asked Questions and to reduce the administrative load on us...
>Thank you.  (Also, the Hotline is automatic and thus available 24 hours a
>day, whereas the administration is a 9am-5pm West Coast time operation.)



======================================================================= 58 ===
Date:    12 Jan 1995 18:20:08 GMT
From:    bm@stieglitz.cs.columbia.edu (Blair MacIntyre)
Subject: HP-UX and shared libraries.

(CC:d to comp.cgcc.help since this is a question about the gcc backend
that m-3 uses, based on gcc 2.5.7)

I'm attempting to get Modula-3 (v3.4) compiled on HPUX using shared
libraries. 

It appears to me that the gcc backend is not generating position
independent code.  I cannot tell gcc to do so using the -fpic option
(says it does not work on the pa architecture), so I don't know what
do try next.

Has anyone gotten gcc to generate position indenpendent code that can
be loaded into a shared library on HPUX 9.x (using ld -b)?
--
Blair MacIntyre -- bm@cs.columbia.edu -- Graduate Student (Graphics and UI Lab)

smail: Dept. of Computer Science, 450 Computer Science Building, 500 W 120 St.,
       Columbia University, New York, NY 10027


======================================================================= 59 ===
Date:    Thu, 12 Jan 95 01:08:22 GMT
From:    lady0065@sable.ox.ac.uk (David J Hopwood)
Subject: Re: Cows, Hogs & Farms

In article <1995Jan9.021043@hobbit>,
Mark S. Hathaway <hathawa2@marshall.edu> wrote:
...
> David Shang wrote:
...
>> In reality, we always have exceptions. We can use covariance to rule out a  
>> general principle and use run-time type check for a few exceptions. As to
>> the animal example, it is clearly worthwhile to divide animals into
>> herbivires, carnivores and (?)(animals eating both food) according to the
>> type of their food. We can use covaraince. But it might be very hard to
>> rule out a general principle for the futher classification for a certain
>> number of animals.
...
>> We are not developing a commercial software for zoologists, are we? These
>> are only pedagogical examples. Be wise to make things as simple as possible
>> -- just for the key points you want to say. 
>
>I have created a few examples in the past which thoroughly confused people
>because they weren't realistic enough.  I'm trying to avoid the sins of
>my past.

Same here.

...
>I'd certainly be interested to read further discussion on the differences
>between these classes and those of Sather & Eiffel.  There seem to be some
>rather major differences.

It might help to read about the typing systems of Cecil, Trellis/Owl, or ML
(and various other functional languages), which use a similar approach to
Cluster.

A paper on the Cecil typing system is at
http://www.cs.washington.edu/research/projects/cecil/www/cecil-spec.html
At least, I think that's the right paper - I can't read postscript on this
terminal to check. Don't get too confused by the stuff on multi-methods - it's
fascinating, but not really relevant. Genericity is described near the end of
the paper.

A good account of dynamic genericity (also called Milner polymorphism) in
functional languages is given in

An Introduction to Functional Programming
Richard Bird and Phillip Wadler
Prentice Hall series in Computing Science
(sorry, don't have the ISBN on me).

Hope this helps,

David Hopwood
david.hopwood@lmh.oxford.ac.uk


======================================================================= 60 ===
Date:    Fri, 13 Jan 1995 00:48:57 +0100
From:    msm13@cus.cam.ac.uk (M.S. Mamo)
Subject: help with threads

I am trying out threads in Modula-3.
The firstthread prints out the 5 times table and the second thread prints
out the 6 times table. However the program prints all of the 6 times table
out and then all of the 5 times table out. I hoped the two would be
interleaved. What am I doing wrong? Could it just be the way threads have
been implemented on our system?

...
BEGIN

firstthread := Thread.Fork(Proc1);
secondthread := Thread.Fork(Proc2);

EVAL Thread.Join(firstthread);

END threadtest.


======================================================================= 61 ===
Date:    Fri, 13 Jan 1995 15:44:23 GMT
From:    olaf@logware.de (Olaf Wagner)
Subject: rel 3.3 and ILU?


Has anybody succeeded in using ILU with rel 3.3 of SRC Modula-3?
Are patches available? If so, any hints where to look for them?

Olaf
-- 
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
\ Olaf Wagner              at Logware GmbH       Schwedenstrasse 9     \
\ olaf@logware.de (work)                         13359 Berlin 65       \
\ wagner@luthien.in-berlin.de (private)          Germany / Deutschland \


======================================================================= 62 ===
Date:    13 Jan 1995 06:21:01 GMT
From:    hansels@hk.super.net (Mr Hansel HC Sin)
Subject: Re: Cows, Hogs & Farms

Alf-Ivar Holm (alfh@gyda.ifi.uio.no) wrote:
: In article <1995Jan3.223031@hobbit> hathawa2@marshall.edu (Mark S. Hathaway) 
writes:

: > I've not seen BETA and have never heard of Cluster.  Could you provide
: > a pointer-->ftp_site or other info. about them?  :-)

: The BETA home page is found at:

: 	http://www.daimi.aau.dk/~beta/info

: I have no info on Cluster.

: 	Affi


======================================================================= 63 ===
Date:    Sat, 14 Jan 1995 03:26:41 GMT
From:    krystof@cs.washington.edu (Krzysztof Zmudzinski)
Subject: Compiling error

I am trying to build m3 release 3.3 on an ALPHA running OSF/1.
I have 150MB of free disk space.

s - creating symbol hash table. Wait...
ar: Error: libm3.a cannot grow sym table: oldmax=864, size=1198614080 
*** error code 1
"/afs/cs.washington.edu/project/spin/krystof/m3/boot-ALPHA_OSF/m3build/template
s/COMMON.BOOT", line 47: command execute failed
*** call stack ***
"/afs/cs.washington.edu/project/spin/krystof/m3/boot-ALPHA_OSF/m3build/template
s/COMMON.BOOT", line 47: call to built-in exec
"./make.boot", line 457: call to procedure boot_lib

Krystof


======================================================================= 64 ===
Date:    Fri, 13 Jan 1995 20:51:13 GMT
From:    lrr@Princeton.EDU (Lawrence R. Rogers)
Subject: Building version 3.4 under Solaris 2.4 with gcc


I've successfully built gcc under Solaris 2.4 without problem.  However when I 
try to build m3cc under version 3.4, I get the following:

gcc  -DIN_GCC -DSVR4  -g   -o genattrtab \
 genattrtab.o rtl.o print-rtl.o rtlanal.o ` case "obstack.o" in ?*) echo obstac
k.o ;; esac ` ` case "gcc"@"alloca.o" in "cc"@?*) echo alloca.o ;; esac ` ` cas
e "" in ?*) echo  ;; esac `   
if cmp -s Makefile md;  \
then                                    \
  echo Using ;  \
  cp  tmp-attrtab.c;    \
else                                    \
  ./genattrtab md > tmp-attrtab.c;      \
fi
*** Error code 139
make: Fatal error: Command failed for target `stamp-attrtab'


Anybody get this one to work?  Thanks for the tip.

 =====   ======= =======	Larry Rogers
=     =     =       =     	Manager, UNIX Systems
=           =       =     	Princeton University
=           =       =     	87 Prospect Avenue, Room 201
=           =       =     	Princeton, NJ 08544
=           =       =     	lrr@Princeton.EDU, princeton!lrr
=           =       =     	Phone: 609-258-6483/6000
=     =     =       =     	FAX:   609-258-1069/3943
 =====   =======    =		NeXT and Sun Mail Happily Accepted




======================================================================= 65 ===
Date:    13 Jan 95 21:19:38 EDT
From:    hathawa2@marshall.edu (Mark S. Hathaway)
Subject: Re: Cows, Hogs & Farms

> In article <1995Jan9.203528.29056@schbbs.mot.com>,
> shang@corp.mot.com (David L. Shang) writes:

>> In article <1995Jan9.005627@hobbit>  writes:

>>> In article <1995Jan6.164948.4782@schbbs.mot.com>,
>>> shang@corp.mot.com (David L. Shang) writes:

>>> ...

>> So, ANIMALT.FOODT implies that a particular food is associated with a
>> particular animal?  How can it be a HERBIVORE and yet eat only one kind
>> of plant?

> It cannot be in reality. I am reluctant to complicate this example.  But to  
> describe a HERBIVORE that eat more than one kinds of food is also possible
> by multiple inheritance:
> 
> 	class COW is HERBIVORE [ FOODT = GRASS ],
> 		     HERBIVORE [ FOODT = HAY ],
> 		     ...
> 
> But there will be a problem when you try to substitude ANIMALT with COW:
> 
> 	class MONOCULTUREFARM  [ANIMALT <: HERBIVORE]
> 	      attr livestock : list[ANIMALT];
> 	      attr foodstock : list[ANIMALT.FOODT];
>  
> 	cow_farm: MONOCULTUREFARM [COW];
> 
> As COW has multiple bases:  HERBIVORE[GRASS], HERBIVORE[HAY], ..., which
> base is used? You have to specify:
> 
> 	grass_farm: MONOCULTUREFARM [COW as HERBIVORE[GRASS]];
> 
> or
> 	hay_farm: MONOCULTUREFARM [COW as HERBIVORE[HAY]];
> 
> In fact, the MONOCULTUREFARM designed here is no longer suitable for an
> animal that eats more than one plant, becase it only keeps one kind of
> food. However, if we could figure out a subclass of PLANT for COW, say,
> COW_FOOD, there is not problem to have HERBIVORE[COW_FOOD] and the
> MONOCULTUREFARM as define above.
> 
> Unfortuantely, in most cases, it is almost impossible to classify herbivores 
 
> according to the food type they eat. This is probably a bad example to  
> demonstrate the covariance. I whould like to use the herbivore/carnivore  
> classification example.

The reason I continue to ask this question is that the first example I gave
didn't bind the animal to the food.  Someone added that later and confused
the entire issue.  See what a mess it makes?

If you have...

         PLANT                     HERBIVORE      
     _____| |_____               _____| |_____    
    |             |             |             |   
   CORN         GRASS          HOG           COW      I'm ignoring LIST
    |             |             |             |       for the moment.
    V             V             V             V   
                           -----------    ----------
                          |   HOG     |  |   COW    |
                          |   FARM    |  |   FARM   |
                          |___________|  |__________|


it would seem much easier to bring the CORN & GRASS to mix separately rather
than saying

     COW inherits HERBIVORE[GRASS]

Also, notice that if you want a heterogeneous FARM you drop back to
using HERBIVORE, but a HERBIVORE isn't necessarily a COW or HOG.  For
a heterogeneous farm you need LIST[COW] & LIST[HOG].  To create a
class which could represent either COW or HOG would be interesting.
I haven't seen any instances of that.  What I have in mind is....

   -- HERBIVORE is the base class
      COW         is HERBIVORE;
      HOG         is HERBIVORE;
      FARM_ANIMAL is COW or HOG;
      FARM        is LIST[FARM_ANIMAL];


>>     procedure feed ( get livestock is in out list(animal);
>>                      get foodstock is in out list(food)   ) is

> Why should you provide additional input/output parameters for feed in
> the class body?

When I was creating this pseudo-code I noticed that there was the
possibility for a class to have more than one piece of data which
represented a part of the object and some of the data might be only
supplementary or temporary.  And, there is the question of whether all
the data in a class should be considered globally shared with all the
methods used by the class.  I decided it would be interesting to add
the "get" to bind a particular data to a method.

It hasn't been roundly praised or condemned.  Mostly people have asked
why it's there.  It's just an idea, not a lifestyle.  :-)


> Why should the feed interfaces be different?

Only to specify those extra parameters with the "get"; which should remain
unseen by the user who sees the interface.


> Agian, I don't consider this herbivore example a good example to demonstrate 
 
> covariance. Lets just take the assumption that COW eat GRASS only and HOG
> eat CORN only, and make things simple. If you don't like the assumption, we
> may consider the animal/herbivore/carnivore example.

Maybe someone could begin by defining "covariance" in words and/or with
an example in code.


Mark S. Hathaway       <hathawa2@marshall.edu>


======================================================================= 66 ===
Date:    14 Jan 1995 23:22:07 GMT
From:    mbk@inls1.ucsd.edu (Matt Kennel)
Subject: Re: Cows, Hogs & Farms

Mark S. Hathaway (hathawa2@marshall.edu) wrote:

: Also, notice that if you want a heterogeneous FARM you drop back to
: using HERBIVORE, but a HERBIVORE isn't necessarily a COW or HOG.  For
: a heterogeneous farm you need LIST[COW] & LIST[HOG].  To create a
: class which could represent either COW or HOG would be interesting.
: I haven't seen any instances of that.  What I have in mind is....

:    -- HERBIVORE is the base class
:       COW         is HERBIVORE;
:       HOG         is HERBIVORE;
:       FARM_ANIMAL is COW or HOG;
:       FARM        is LIST[FARM_ANIMAL];

-- Sather

type $HERBIVORE is
       try(food:$PLANT);
end;

type $HERBIVORE{MYFOOD < $PLANT} is
	try(food:$PLANT);
	eat(food:MYFOOD);
end;


class COW < $HERBIVORE{GRASS} is
	-- blah blah blah implementation
end;

class HOG < $HERBIVORE{CORN} is
	-- implementation
end;

type $IOWA_FARM_ANIMAL > COW,HOG is
      try(food:$PLANT);
end;

class IOWAFARM is
	-- has hogs and cows.

	attr animals: LIST{$FARM_ANIMAL}
	attr food : LIST{$PLANT};

	feed is
	   loop
		animals.elt!.try(food.elt!);
	   end;
	end;

	feed_corn is
	    -- Cluster does this one a little cleaner
	    loop
		f ::= food.elt!;	
		a ::= animals.elt!;
		typecase f
		when CORN
		    typecase a
		    when $HERBIVORE{CORN} then a.feed(f);  end;
		end;
	    end;
	end;
end;

In general Cluster lets you get at the foodtype for animals for run-time
selection OUTSIDE their class easily, in Sather it's usually easier to put
the typecase inside the 'try'.


: Mark S. Hathaway       <hathawa2@marshall.edu>

--
-Matt Kennel  		mbk@inls1.ucsd.edu
-Institute for Nonlinear Science, University of California, San Diego
-*** AD: Archive for nonlinear dynamics papers & programs: FTP to
-***     lyapunov.ucsd.edu, username "anonymous".


======================================================================= 67 ===
Date:    16 Jan 1995 14:37:57 GMT
From:    c4craig@csn.net (Craig Anderson)
Subject: trestle for NT?

The m3 3.4 announcement mentions a port to Windows/NT without Trestle.
Is a Trestle port to NT planned?

Craig Anderson
craig@c4.com



======================================================================= 68 ===
Date:    15 Jan 1995 17:05:57 GMT
From:    danan@cs.concordia.ca (DANAN itai)
Subject: Modula-3 for OS/2

Does anyone know of a public domain Modula-3 compiler for OS/2?
If so, where can I get it?

Thanks in advance, Itai

danan@concordia.ca



======================================================================= 69 ===
Date:    16 Jan 1995 17:48:17 GMT
From:    bm@shadow.cs.columbia.edu (Blair MacIntyre)
Subject: which "pass" is the linker?

I'm trying to properly configure modula 3 for the Iris, and the linker
spews a lot of messages of the form:
libm3ui.a(PackSplit.mo): does not have gp tables for all it's sectons

In the template, there is a comment of the form:

   % "-zJ10",
   % The option "-zJx1" specifies that pass "x" is "noisy", "-zJx0"
   % specifices that it's not.  The default is to assume that passes
   % are not noisy.  The driver collects the standard output of noisy
   % passes in a file and then deletes the file, unless "-keep" or
   % "-verbose" is specified.

So, which pass is the linker?  I'd like to tell M3 that it's noisy.
--
Blair MacIntyre -- bm@cs.columbia.edu -- Graduate Student (Graphics and UI Lab)

smail: Dept. of Computer Science, 450 Computer Science Building, 500 W 120 St.,
       Columbia University, New York, NY 10027


======================================================================= 70 ===
Date:    17 Jan 95 08:32:44
From:    dagenais@notung.vlsi.polymtl.ca (Michel Dagenais)
Subject: Re: Modula-3 for OS/2


>From the FAQ. The last persons known to be working on such a port were
Hendrik Boom hendrick@CAM.ORG and Craig Andrew Kingston 
ckingsto@undergrad.math.uwaterloo.ca.
--

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



======================================================================= 71 ===
Date:    17 Jan 1995 14:59:25 GMT
From:    mester@ls4.informatik.uni-dortmund.de (Arnulf Mester)
Subject: yacc/bison-equivalent for M3?

Are any parser generators like yacc/bison (or more comfortable ones
like eli/cocktail) or equivalents in use in the M3 community?

I am interested in integration and usage experiences, like
degree of manual intervention, readability of code, lexical
analysis software used (apart from M3.Lex) etc.

If requested by e-mail, I would mail back a summary.

Thanks in advance,
kind regards,

P.S. I do know about m3tk and MetaParser in the M3 distribution.

Arnulf Mester, Informatik IV, University, D-44221 Dortmund, Germany
Dipl.-Inform.  * Phone: +49 231 755-4662 (Q), Secr.: -2596, Fax: -4730
	       * http://ls4-www.informatik.uni-dortmund.de/MA/am/pie.html
               * Computer Networks & Distributed Systems Group (Prof.Dr.H.Krumm
)

-- 

Arnulf Mester, Informatik IV, AG Rechnernetze u. verteilte Systeme
Campus Sued, GB V/509, Tel. 755-4662, Sekretariat -2596, Fax -4730


======================================================================= 72 ===
Date:    Tue, 17 Jan 95 15:49:50 -0800
From:    najork@pa.dec.com (Marc Najork)
Subject: Re: trestle for NT?


Yes, I am working on such a port.

However, I can't give you any planned release date.


======================================================================= 73 ===
Date:    17 Jan 1995 19:39:29 GMT
From:    Quentin Stafford-Fraser <fraser@europarc.xerox.com>
Subject: Re: Building version 3.4 under Solaris 2.4 with gcc

Peter Klein <pk@i3.informatik.rwth-aachen.de> wrote:

>  - Use another compiler for the backend. gcc 2.6.0 should do.

No - I tried 2.6.0 at first, then upgraded my gcc to 2.6.3 hoping 
that would fix it :-)

In the end I just copied the binary of m3cgc1 from Michel's site.
The build is steaming along now! Won't help Solaris people, though.

Quentin


======================================================================= 74 ===
Date:    18 Jan 1995 10:13:26 GMT
From:    anderse@dna.lth.se (Anders Edenbrandt)
Subject: Re: Building version 3.4 under Solaris 2.4 with gcc

In article <1995Jan13.205113.11219@Princeton.EDU>,
Lawrence R. Rogers <lrr@Princeton.EDU> wrote:
>
>I've successfully built gcc under Solaris 2.4 without problem.  However when I
 try to build m3cc under version 3.4, I get the following:
>
>  ./genattrtab md > tmp-attrtab.c;      \
>make: Fatal error: Command failed for target `stamp-attrtab'
>

I managed to get past this problem by replacing m3cc/gcc/va-sparc.h
with the same file from a more recent version of gcc. Version 2.6.0
will do, in which case the file is called gcc-2.6.0/include/va-sparc.h.

Anders Edenbrandt
Dept. of Computer Science
Lund University
Lund, Sweden



======================================================================= 75 ===
Date:    18 Jan 1995 09:38:11 GMT
From:    charly@samsoef.ifi.uni-klu.ac.at (Karl-Heinz EDER)
Subject: Announcement of M3PC-Klagenfurt


ANNOUNCEMENT
------------

We have the pleasure to announce that the  newest release of M3PC-Klagenfurt
is immediately available on the gatekeeper!

What is M3PC-Klagenfurt ?
--------------------------

   M3PC-Klagenfurt  (previously called M3PC)  is  a  port  of  the  Modula-3
   compiler release 2.09 to the MSDOS-PC.

   It translates Modula-3 source into C soure. Therefore you have to install
   the GNU C-compiler DJGPP as well,  which is distributed, too (see 4). You
   may of course  use a newer  release of the  GNU C-compiler  or additional
   compatible libraries.



What's new ?
-------------

   The new M3PC-Klagenfurt release supports the following (new) features:

          * library to access DOS files and directories
          * threads
          * pickles
          * a shell
            (incl. automatic compilation and UNIX like long filenames)


Hard- and Software Requirements
--------------------------------

   (a) Hardware:
       You will need a PC:
           *  80486 or 80386 with floatingpoint-coprocessor,
           *  at least 4 but preferable 8 MByte of RAM,
           *  20 MByte disk space free at least.

   (b) Software:
           * DOS 5.00 or higher


Necessary Files for Installation
---------------------------------

   The necessary  files  are  available  at  "gatekeeper.dec.com"  in  the
   directory "pub/DEC/Modula-3/contrib/m3pc":

              TAR      EXE        39,353 11-07-94  10:11a
              INSTALL  TXT         5,325 11-10-94   4:57p
              M3       TAR     6,799,360 11-07-94   4:26p
              DJGPP    TAR     6,809,600 11-07-94  11:33a
              M3SRC    TAR     6,871,040 11-07-94  11:36a
              README               5,331 11-10-94   5:40p



For further details please see the files README and INSTALL.TXT.


What is still to come?
-----------------------

A  student-friendly environment  with integrated  editor-browser-compiler
is in the test-phase and should be shipped in course of March.
The main purpose of the system is to provide an environment for beginners
and hide unnecessary details of the operating system and run-time support.

It will also be the basis of the examples of the book
"Programming in style -- An introduction into programming with Modula-3"
which is also intended first of all for first- and second-semester
computer science students.


Enjoy

     L.Bvszvrmenyi, C.Weich, K.-H.Eder
     University of Klagenfurt / AUSTRIA
     January, the 18th 1995


======================================================================= 76 ===
Date:    Wed, 18 Jan 1995 11:37:30 GMT
From:    joel@bris.ac.uk (Joel Crisp)
Subject: Re: Building version 3.4 under Solaris 2.4 with gcc

Peter Klein (pk@i3.informatik.rwth-aachen.de) wrote:
: lrr@Princeton.EDU (Lawrence R. Rogers) wrote:
: >
: > 
: > I've successfully built gcc under Solaris 2.4 without problem.  However whe
n I try to build m3cc under version 3.4, I get the following:
: > 
: > gcc  -DIN_GCC -DSVR4  -g   -o genattrtab \
: >  genattrtab.o rtl.o print-rtl.o rtlanal.o ` case "obstack.o" in ?*) echo ob
stack.o ;; esac ` ` case "gcc"@"alloca.o" in "cc"@?*) echo alloca.o ;; esac ` `
 case "" in ?*) echo  ;; esac `   
: > if cmp -s Makefile md;  \
: > then                                    \
: >   echo Using ;  \
: >   cp  tmp-attrtab.c;    \
: > else                                    \
: >   ./genattrtab md > tmp-attrtab.c;      \
: > fi
: > *** Error code 139
: > make: Fatal error: Command failed for target `stamp-attrtab'
: > 
: > 
: > Anybody get this one to work?  Thanks for the tip.
: > 

: I know this is not what you want to hear, but the same problem occurs on
: SunOS 4.1.3. Apparantly, gcc versions 2.6.1 to 2.6.3 are not willing
: to compile the m3cc backend which is based on gcc 2.5.7. The problem
: seems to be an incompatibility in the varargs library. Solutions:
:  - Update m3cc to a newer gcc version (Bill?)
:  - Work around the error (Some gcc expert?)


******* GCC expert hears you
Go to /usr/local/lib/gcc-lib/sparc-sun-solaris2.3/2.6.0
 ( or wherever the equivalent is for your system )
copy "specs" to another name.
edit specs and remove the -D__GCC_NEW_VARARGS 

This fixes the problem.
*******

:  - Use another compiler for the backend. gcc 2.6.0 should do.

: Peter
: ---
: Peter Klein                        E-Mail: pk@i3.informatik.rwth-aachen.de
: Lehrstuhl fuer Informatik III      Tel.: +49/241/80-21311
: Ahornstrasse 55                    Fax.: +49/241/8888-218
: RWTH Aachen
: 52074 Aachen
: Germany


Joel

Joel.Crisp@bris.ac.uk 



======================================================================= 77 ===
Date:    19 Jan 1995 18:39:29 GMT
From:    bm@shadow.cs.columbia.edu (Blair MacIntyre)
Subject: modula3.el - blink-matching-open problem in Emacs 19 ...


I was just wonder if anyone else had this problem and had a workaround.

When I close a comment in Emacs, I get the error 

Signalling: (wrong-type-argument number-or-marker-p nil)
  blink-matching-open()

This doesn't seem to happen in Emacs-18, so I'm wondering if it's
something weird with 19, and if anybody has a fix.  Turning of
blink-matching-paren obviously fixes it, but that's not entirely
satisfactory.  

Thanks.
--
Blair MacIntyre (bm@cs.columbia.edu), Graduate Student (Graphics and UI Lab)

smail: Dept. of Computer Science, 450 Computer Science Building, 500 W 120 St.
       Columbia University, New York, NY 10027


======================================================================= 78 ===
Date:    20 Jan 1995 21:33:50 GMT
From:    nayeri@gte.com (Farshad Nayeri)
Subject: ANNOUNCEMENT: Report of the Third Modula-3 User Group, OOPSLA'94


ANNOUNCEMENT

  WHAT : Informal Report of the Third Modula-3 User Group Meeting 
 WHERE : ftp://ftp.gte.com/pub/m3/m3ug/m3ug.html

         The full report contains a more detailed description as well
         as copies of some of presenters' slides.  This message
         contains only a capsule summary of the meeting. For the full
         report, follow the URL above.


CAPSULE SUMMARY

The Third Modula-3 User Group Meeting at OOPSLA'94 was a success
thanks to the participants and presenters! In the short time of two
hours, six presenters talked about their experiences with Modula-3 and
what they are doing with it. The attendance was solid (25-30 people),
given our limited public announcement and the timing of the event.

The meeting included several presentations by people who have been
using Modula-3 in the past few years. The summary contains references
to some of their slides and a brief a overview of the meeting.

Although there was no discussion section during the meeting itself,
some of the participants joined us at a round-table discussion of
Modula-3 and its needs before it can become a popular programming
platform.


PRESENTATIONS

     Geoff Wyant: Modula-3 at Sun Microsystems Laboratories      [slides]
   Luca Cardelli: Obliq and Visual Obliq                         [slides]
      Eliot Moss: History and status of UMass work on Modula-3 
   Steve Freeman: Adding video capabilities to Trestle/Modula-3  [slides]
  Mike Spreitzer: Inter-Language Unification                     [slides]
  Farshad Nayeri: Building a prototype distributed object systems


DISCUSSIONS

After the meeting, some of us got together to discuss the state of
Modula-3. Some of the topics discussed were:

                -  Modula-3 as a low-level language and a competitor of C
                -  Modula-3 as a high-level language and a competitor
                   of Eiffel, Smalltalk, and Ada
                -  Exposure in the computer magazines
                -  Commercial Support


NEXT MEETING

We plan to arrange for the next Modula-3 User Group meeting at
COOTS'95, or Conference on Object-Oriented Technologies, Monterey,
California, USA during summer of 1995. Please let us know if you have
suggestions about format, content, or place of the next meeting.

WHAT IS MODULA-3?  

Modula-3 is a modular programming language; while preserving a safe
type system, Modula-3 provides facilities for exception handling,
concurrency, object-oriented programming, automatic garbage
collection, and systems programming, making it both a practical
implementation language for large software projects and an excellent
teaching language. An implementation of Modula-3 is available freely
from Digital Equipment Corporation's Systems Research Center.

For more information, see Modula-3 Home Page:
    http://www.research.digital.com/SRC/modula-3/html/home.html


CONTACT

  Farshad Nayeri:  nayeri@gte.com
     Geoff Wyant:  geoff.wyant@east.sun.com


--
Farshad Nayeri
nayeri@gte.com


======================================================================= 79 ===
Date:    20 Jan 1995 16:22:31 GMT
From:    
Subject: US-MA-Job: Distributed Computing @ Sun East


 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
 1/20/95                      /\ 
                              \ \
                             \ \ /        /\  | | |  |
                            \ \ / /       \   | | |\ |
                           / \/ \/ /\      \  | | | \|
                          / /     / /     \/  |_| |  |
                          \/ /\ /\ /
                            / / \ \       MICROSYSTEMS
                             / \ \         East Coast
 Chelmsford, MA               \ \         Development
                               \/              Center
 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		Member of Technical Staff
         Large-Scale Distributed Computing - SunLabs
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Individual contributor to join a team investigating approaches to
reliable, large-scale distributed computing. Ideal candidate will 
have an advanced degree and at least 2 years industry experience,
including experience in taking a product to a form that could be 
shipped to customers. **Must be well versed in distributed computing,
object-oriented programming and the design of protocols for
reliability.**  Knowledge of Modula-3 desirable but not required.
Must be able to work with a small group of highly technical and
outspoken people in an experimental and rapidly changing computing
environment.
 
Recent MS / PhD candidates considered if a top grad from top school
with some industry experience:
**well versed in distributed computing, object-oriented 
  programming and the design of protocols for reliability.** 

Eligibility to work in US required.
 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
             -> Position based in Chelmsford, Mass.<-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        Please send resume to:  usmail: Sun Microsystems
                                        2 Elizabeth Drive
                                        Chelmsford, MA 01824
                                        ATTN: NET/LABS
 
                                email:  staffing@east.sun.com (ASCII)
 
                                fax:    508 442 0011





======================================================================= 80 ===
Date:    20 Jan 1995 22:10:52 GMT
From:    nayeri@gte.com (Farshad Nayeri)
Subject: Re: Request for status on v. 3.4 (SPARC)


Stephen Schaub asks about the status of version 3.4 on SPARCs.

Our installation of Modula-3 3.4 works just fine. There are a few
minor problems when you try to do the build. If you can't wait, I am
sure Bill or Michel can forward you the list of patches that you have
to make (I didn't see some of the required changes in bugs&patches
page of SRC Modula-3 home page, but I wasn't looking hard.)

Someone also asked about run-time sizes (was it you, Stephen?). Here
are some numbers. Note that I know nothing about performance
measurement, and these are very crude at best.

                 executable   build directory    time(1) output
                 size(bytes)   size (blocks)       see man time

3.3 hello world    1204224          1130     7.7 real,4.2 user,1.1 sys
3.4 hello world    1105920          1197     9.6 real,5.9 user,1.3 sys

3.3 dom app        802816           2454     240.6 real,132.1 user,26.4 sys
3.4 dom app        614400           2258     139.0 real, 61.2 user,14.5 sys

All builds were as warm as I could make my SPARC 20s running SunOS
4.1.3 with 64Mbytes RAM. Modula-3 was running over a pretty slow NFS
connection (sigh!) All builds are with the -g flag on (basically the
same setups as the default.)

"hello world" was compiled with "standalone()" in m3makefile. That's
why it's bigger.

"dom app" uses formsvbt and tcp packages among other things. It is a
pretty large application, and it is using the shared libraries.

Please don't take these numbers seriously, but it looks like the
compiler is faster and creates smaller executables.

Have a nice weekend!

-- Farshad

[I am typing this in a hurry. Don't be surprised if there is a mistake!]

--
Farshad Nayeri
nayeri@gte.com


======================================================================= 81 ===
Date:    20 Jan 1995 19:52:28 GMT
From:    schaub@ponder.csci.unt.edu (Stephen Schaub)
Subject: Request for status on v. 3.4 (SPARC)

A couple of weeks ago it was announced that SRC Modula-3 3.4 was out but
that some final testing was needed to stabilize the release.  I'm interested
in the SPARC flavor--is it ready to go?  The semester has started and 
my students will appreciate having the enhanced run-time error info.

Thanks,
Stephen Schaub
schaub@cs.unt.edu
TF, University of North Texas


======================================================================= 82 ===
Date:    20 Jan 1995 23:03:39 GMT
From:    detlefs@src.dec.com (Dave Detlefs)
Subject: Re: modula3.el - blink-matching-open problem in Emacs 19 ...


Blair MacIntyre writes:

    I was just wonder if anyone else had this problem and had a workaround.

    When I close a comment in Emacs, I get the error 

    Signalling: (wrong-type-argument number-or-marker-p nil)
      blink-matching-open()

    This doesn't seem to happen in Emacs-18, so I'm wondering if it's
    something weird with 19, and if anybody has a fix.  Turning of
    blink-matching-paren obviously fixes it, but that's not entirely
    satisfactory.  

I don't have this problem with emacs19.  Here is the version of
modula3.el we're currently using at SRC; perhaps yours is older...

----------------------------------------------------------------------
;;; Last modified on Fri Jan 20 15:03:29 PST 1995 by detlefs
;;;      modified on Fri May 15 17:13:12 PDT 1992 by heydon

;;;      modified on Thu Apr 23 17:45:03 PDT 1992 by muller
;;;      modified on Fri Feb  2 13:04:24 1990 by discolo
;;;      modified on Tue May  2 21:59:35 1989 by ellis
;;;      modified                             by Trevor Morris
;;;      modified                             by Tom Perrine
;;;      modified                             by Michael Schmidt
;;;      modified                             by Peter Robinson
;;;      modified                             by mjordan

;; LCD Archive Entry:
;; modula3|Eric Muller|muller@src.dec.com|
;; Modula-3 mode.|
;; 92-04-17||~/modes/modula3.el.Z|

(require 'cl)

(provide 'modula3)

;;; ---------- Syntax Table and Keymap (Added by TEP) ----------

(defvar m3::mode-abbrev-table nil
  "Abbrev table in use in C++-mode buffers.")
(define-abbrev-table 'm3::mode-abbrev-table ())

(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 ?* ". 23" table)
    (modify-syntax-entry ?\( "()1" table)
    (modify-syntax-entry ?\) ")(4" 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)))

(defvar m3::mode-map nil
  "Keymap used in Modula 3 mode.")

(defvar m3::screen-pool nil
  "Pool of sceens for m3")

(defvar m3::mouse-map nil
  "mouse map for m3-mode.")

(defun m3::setup-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 (not m3::mode-map)
      (progn
	(setq m3::mode-map (make-sparse-keymap))
	(define-key m3::mode-map "\t" 'm3::abbrev-and-or-indent)
	(define-key m3::mode-map "\M-\t" 'm3::ident-complete)
	(define-key m3::mode-map "\C-ca" 'm3::toggle-abbrev)

	(define-key m3::mode-map "\C-ci" 'm3::show-interface)
	(define-key m3::mode-map "\C-cm" 'm3::show-implementation)
	(define-key m3::mode-map "\C-cs" 'm3::show-spec)
	(define-key m3::mode-map "\C-ct" 'm3::show-trait)

	(define-key m3::mode-map "\C-cb" 'm3::pp-buffer)
	(define-key m3::mode-map "\C-cu" 'm3::pp-unit)
	(define-key m3::mode-map "\C-cr" 'm3::pp-region)

	(define-key m3::mode-map "\M-\C-a" 'm3::beginning-of-defun)
	(define-key m3::mode-map "\M-\C-e" 'm3::end-of-defun)
	(define-key m3::mode-map "\C-c\C-f" 'm3::forward-sexp)
	(define-key m3::mode-map "\C-c\C-b" 'm3::backward-sexp)
	))
  )


;;; --------------- Constant and global variable declarations --------------

(defconst m3::identifier-char-re "[a-zA-Z0-9_]")
(defconst m3::alpha-char-re "[a-zA-Z_]")
(defconst m3::not-identifier-char-re "[^a-zA-Z0-9_]")

(defconst m3::identifier-re
  (concat "\\b" m3::alpha-char-re m3::identifier-char-re "*\\b"))

(defconst m3::intlit-re "\\(0\\|[1-9][0-9]*\\)")

(defconst m3::poss-qual-ident-re
  (concat "\\(" "\\(" m3::identifier-re "\\.\\)?" m3::identifier-re "\\.\\)?"
	  m3::identifier-re))

(defconst m3::com-start-re "\\((\\*\\|<\\*\\)")
(defconst m3::com-end-re "\\(\\*)\\|\\*>\\)")
(defconst m3::com-start-or-end-re
  (concat "\\\(" m3::com-start-re "\\|" m3::com-end-re "\\)"))

(defconst m3::whitespace-char-re "[ \t]")
(defconst m3::whitespace-re "[ \t]+")
(defconst m3::poss-whitespace-re "[ \t]*")
(defconst m3::poss-whitespace-nl-re "[ \t\n]*")
(defconst m3::whitespace-line-re "^[ \t]*$")


(defconst m3::char-lit-re "'\\([^\\]\\|\\\\..?.?\\)'")

(defconst m3::range-end-re
  (concat "\\(" m3::poss-qual-ident-re "\\|" m3::intlit-re "\\|"
	  m3::char-lit-re "\\)"))

(defconst m3::range-re
  (concat m3::range-end-re m3::poss-whitespace-re "\\.\\."
	  m3::poss-whitespace-re m3::range-end-re))
  
  
(defconst m3::case-label-re
  (concat "\\(" m3::poss-qual-ident-re "\\|"
	  m3::char-lit-re "\\|"
	  m3::intlit-re "\\|"
	  m3::range-re
	  "\\)"))

(defconst m3::handler-start-re
  (concat "\\(|[ \t]*\\)?\\("
	  (concat "\\b" m3::poss-qual-ident-re m3::poss-whitespace-re
		  "(" m3::poss-whitespace-re m3::identifier-re
		  m3::poss-whitespace-re ")" )
	  "\\|"
	  (concat "REF" m3::whitespace-re ".*"
		  "(" m3::poss-whitespace-re m3::identifier-re
		  m3::poss-whitespace-re ")" )
	  "\\|"
	  (concat m3::case-label-re
		  (concat "\\(" m3::poss-whitespace-re ","
			  m3::poss-whitespace-nl-re m3::case-label-re "\\)*"))
	  
	  "\\)" m3::poss-whitespace-re "=>"))


(defconst m3::object-re
  (concat "\\(" m3::identifier-re "[ \t]+\\)?\\(BRANDED[ \t]+"
	  "\\(\"[^\"]+\"\\)?[ \t]+\\)?OBJECT"))


(defconst m3::part-starters
  (concat
   "\\bINTERFACE\\b\\|\\bMODULE\\b\\|\\bIMPORT\\b\\|\\bFROM\\b\\|"
   "\\bTYPE\\b\\|\\bEXCEPTION\\b\\|\\bVAR\\b\\|"
   "\\bPROCEDURE\\b\\|\\bREVEAL\\b\\|\\bCONST\\b\\|\\bBEGIN\\b")
  "These are the patterns that can start lines and change the indentation
of the following line.")


(defconst m3::keyword-endable-ssl-introducers
  (concat
   "\\bTYPE\\b\\|\\bVAR\\b\\|"
   "\\bRECORD\\b\\|\\bOBJECT\\b\\|\\bMETHODS\\b\\|\\bOVERRIDES\\b\\|"
   "\\bBEGIN\\b\\|\\bTRY\\b\\|\\bEXCEPT\\b\\|"
   m3::handler-start-re "\\|"
   "\\bFINALLY\\b\\|\\bLOOP\\b\\|\\bTHEN\\b\\|\\bELSE\\b\\|\\bREPEAT\\b\\|"
   "\\bDO\\b\\|\\bOF\\b\\|\\bREVEAL\\b\\|\\bCONST\\b"))

(defconst m3::statement-list-starter
  (concat
   "\\bBEGIN\\b\\|\\bTRY\\b\\|\\bEXCEPT\\b\\|"
   m3::handler-start-re "\\|"
   "\\bFINALLY\\b\\|\\bLOOP\\b\\|\\bTHEN\\b\\|\\bELSE\\b\\|\\bREPEAT\\b\\|"
   "\\bDO\\b"))

;;; These keywords have the property that they affect the indentation if they
;;; occur at the beginning of a line.
(defconst m3::keyword-line-starters
  (concat
   "\\bTYPE\\b\\|\\bPROCEDURE\\b\\|\\bEXCEPTION\\b\\|"
   "\\bVAR\\b\\|\\bBEGIN\\b\\|\\bTRY\\b\\|\\bEXCEPT\\b\\|"
   m3::handler-start-re "\\|"
   "|\\|\\bFINALLY\\b\\|\\bLOOP\\b\\|\\bTHEN\\b\\|\\bELSIF\\b\\|"
   "\\bIF\\|ELSE\\|WHILE\\|REPEAT\\|"
   "WITH\\|FOR\\b\\|DO\\|CASE\\|\\bOF\\b\\|TYPECASE\\|LOCK\\|CONST\\|FROM\\|"
   "REVEAL\\|METHODS\\|OVERRIDES"))


(defconst m3::multi-keyword-line-prefix
  (concat
   "\\("
   ;; ...a PROCEDURE at the start of a line that ends
   ;; with an equals
   "^PROCEDURE[^\n]*=" "\\|"
   ;; ... or an IF or ELSEIF that ends with a THEN
   "\\(IF\\|ELSIF\\)[^\n]*THEN" "\\|"
   ;; ... or a WHILE, WITH, FOR, or LOCK that ends with a DO
   "\\(WHILE\\|WITH\\|FOR\\b\\|LOCK\\)[^\n]*DO" "\\|"
   ;; ... or a FOR that ends with a TO or BY
   "FOR[^\n]*\\(DO\\|BY\\)" "\\|"		  
   ;; ... or a CASE or TYPECASE that ends with a OF
   "\\(CASE\\|TYPECASE\\)[^\n]*OF" "\\|"
   ;; ... or at a handler-start that ends with a "=>"
   "\\(|\\|\\)[ \t]*" m3::handler-start-re
   "\\)"
   ))

(defconst m3::multi-keyword-lines
  (concat m3::multi-keyword-line-prefix 
	  "[ \t]*\\($\\|(\\*\\)"))


(defconst m3::statement-starters
  (concat
   "BEGIN\\b\\|TRY\\b\\|LOOP\\b\\|IF\\b\\|WHILE\\b\\|REPEAT\\b\\|"
   "WITH\\b\\|FOR\\b\\|CASE\\b\\|TYPECASE\\b\\|LOCK\\b")
  "These are the patterns that can start lines and change the indentation
of the following line.")



(defconst m3::keyword-ssl-enders
  (concat "\\(|\\|\\bEXCEPT\\b\\|\\bFINALLY\\b\\|\\bELSIF\\b\\|"
	  "\\bELSE\\b\\|\\bUNTIL\\b\\|\\bEND\\b\\)"))

(defconst m3::left-parens
  "\\((\\|\\[\\|{\\)")
(defconst m3::right-parens
  "\\()\\|\\]\\|}\\)")

(defconst m3::statement-keywords
  "RETURN\\|RAISE\\|EXCEPTION\\|IMPORT\\|WITH")

(defconst m3::end-matchers
  (concat
   "\\bRECORD\\b\\|\\bOBJECT\\b\\|\\bBEGIN\\b\\|\\bTRY\\b\\|\\bLOOP\\b\\|"
   "\\bIF\\b\\|\\bWHILE\\b\\|\\bWITH\\b\\|\\bFOR\\b\\|\\bCASE\\b\\|"
   "\\bTYPECASE\\b\\|\\bLOCK\\b\\|\\bINTERFACE\\b\\|\\bMODULE\\b\\|"
   "\\bGENERIC\\b"))


(defconst m3::same-line-ssl-keywords
  "\\bVAR\\b\\|\\bTYPE\\b\\|\\bCONST\\b\\|\\bEXCEPTION\\b\\|\\bREVEAL\\b"
  "These are the keywords that can be followed by an SSL that begins on
the same line -- if so, indent to the level of the first elem.")

(defconst m3::case-starters
  "TRY\\|CASE\\|TYPECASE")

;;; ------ Variables that control indentation behavior ------------

(defvar m3::standard-offset 2)
(defvar m3::continued-line-offset 2)
(defvar m3::case-offset 0)
(defvar m3::open-paren-offset 4)
(defvar m3::open-paren-sep 0)
(defvar m3::proc-param-from-proc-keyword t)
(defvar m3::assign-offset 4)
(defvar m3::RAISES-offset 4)

(defvar m3::follow-continued-indent t)

(defvar m3::END-undent 2)
(defvar m3::METHODS-undent 2)
(defvar m3::OVERRIDES-undent 2)
(defvar m3::EXCEPT-undent 2)
(defvar m3::VERT-undent 2)
(defvar m3::handler-start-undent 0)
(defvar m3::EXCEPT-undent 2)
(defvar m3::UNTIL-undent 2)
(defvar m3::FINALLY-undent 2)
(defvar m3::ELSIF-undent 2)
(defvar m3::ELSE-undent 2)

(defvar m3::DO-undent 1)
(defvar m3::OF-undent 1)
(defvar m3::THEN-undent 1)

(defvar m3::OBJECT-undent 1)
(defvar m3::RECORD-undent 1)

;;;  --------  Variables controlling keyword-completion and end-matching.

(defvar m3::abbrev-enabled t
  "*Non-nil indicates TAB should complete keywords.")

(defvar m3::electric-end 'proc-mod
  "*If the value of this variable is 'proc-mod or 'all, a TAB that
completes an END, or occurs after a complete END, may cause some text to
be inserted after the END.  If the value is 'proc-mod and the END
completes the main block of a procedure or a module or interface,
fills in the name of the procedure, module, or interface, and a
semi-colon or period as appropriate.  If the value is 'all, works as
for 'proc-mod, but also adds a comment containing the keyword starting
the construct completed by other END's.  If the value is nil, no text
is added.")


(defvar m3::blink-end-matchers t
  "*Non-nil causes a TAB that completes an END or occurs after a
completed END to momentarily move the cursor to the beginning of the
keyword that starts the construct completed by the END.")

;;; ----------------------------------------------------------------------
;;; NOT USER SETTABLE.
;;; These variables enable us to "cycle through" a list of possible
;;; completions when the prefix the user typed was ambiguous.  If the
;;; point is at (m3::cur-keyword-completion-start +
;;; m3::cur-keyword-completion-len nil) and
;;; m3::cur-keyword-completions is non-nil, we substitute the first
;;; element of the list for the current completion, and rotate the list.

(defvar m3::cur-keyword-completion-start (make-marker)
  "A marker indicating the start of the last word that was keyword-completed.")

(defvar m3::cur-keyword-completion-len nil
  "The length of the completed keyword at the time of completion, to allow
us to determine if the user has entered more text.")

(defvar m3::cur-keyword-completions nil
  "A list of the strings that matched the originally input keyword text.")


;;; ------ THE MAIN ROUTINE - SETS UP MODULA-3 MODE --------------

  
(defun modula-3-mode ()
  "This is a mode intended to support program development in Modula 3.

You can avoid tedious entry of constructs involving long uppercase
keywords by using 'abbrev-mode.'  When m3::abbrev-enabled is non-nil,
TAB typed at the end of a word completes just that current word as a
keyword.  This mode analyzes the context to restrict the choices
admitted by partial prefixes to as small a set as possible.  If more
than 1 choice remain after this winnowing, they are ordered according
to their popularity (assigned in an ad hoc manner by me, dld, and
easily changed), and the first completion is performed, with a message
that other completions are possible.  If the choice is wrong, hitting
TAB immediately will cycle through the other choices.

There are two independent mechanism for indenting/prettyprinting
text.  The main addition that I (dld) have made is adding the style of
'electric' indentation normally associated with gnuemacs language
modes.  Basically, all you need to know is that TAB, in addition to
completing keywords, also indents the current line properly.

The other mechanism uses a pretty printer (m3pp) that runs as a
separate process.  The command m3pp-region and m3pp-unit, and the
variable m3pp-options are used to apply m3pp to a portion of the
buffer.

Another new feature is END-matching and completion.  Various non-nil
values of the variable 'm3::electric-end' cause hitting TAB on a line
containing just an END to do things like fill in the name of the
procedure, module, or interface, or the keyword that starts the
construct that the END completes.  Another, independent, variable,
'm3::blink-end-matchers', temporarily blinks the curser at the
beginning of the construct that the END matches.

Another convenient feature is that beginning-of-defun, end-of-defun,
forward-sexp, and backward-sexp have been given appropriate Modula-3
definitions, and these functions have been bound to the standard keys.

The following list gives the key bindings.
\\{m3::mode-map}"

  (interactive)
  (kill-all-local-variables)
  (m3::setup-mode-map)
  (use-local-map m3::mode-map)
  (setq major-mode 'modula-3-mode)
  (setq mode-name "Modula 3")
  (setq local-abbrev-table m3::mode-abbrev-table)
  (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 "(\\*+[ \t]*")
  (make-local-variable 'comment-multi-line)
  (setq comment-multi-line t)
  (make-local-variable 'comment-indent-function)
  (setq comment-indent-function 'c-comment-indent)
  (make-local-variable 'parse-sexp-ignore-comments)
  (setq parse-sexp-ignore-comments t)

  (run-hooks 'm3::mode-hook))


;;; -------------------- Electric indentation --------------------


(defun m3::indent-line ()
  "Indent the current-line."
  (interactive)
  (m3::indent-line-work t))

(defun m3::indent-line-work (electric)
  ;; If in unterminated string, give an error.  If in comment and
  ;; electric, indent like previous line.
;;;  (message "indent-line-work") (sit-for 2)
  (let ((string-comment-state (m3::in-comment-or-string)))
;;;    (message "string-comment-state = %s" string-comment-state) (sit-for 2)
    (cond
     ((eq string-comment-state 'string)
      (beep)
      (message "Unterminated Text literal..."))
     ((eq string-comment-state 'comment)
      (if electric
	  (let ((cur-point (point)))
	    (beginning-of-line)
	    (m3::skip-whitespace-in-line)
	    (cond
	     ;; If the current line begines with a close comment,
	     ;; indent it to the level of the matching start comment.
	     ((save-excursion
		(beginning-of-line)
		(m3::skip-whitespace-in-line)
		(looking-at "*)"))
	      (m3::indent-to
	       cur-point
	       (save-excursion
		 (beginning-of-line)
		 (m3::skip-whitespace-in-line)
		 (forward-char 2)
		 (m3::skip-comment-backward (point-min) t)
		 (current-column))))

	     ;;; If the current line begins with an open-comment, and
	     ;;; the opened comment is not nested, indent like a code line.
	     ((save-excursion
		(beginning-of-line)
		(m3::skip-whitespace-in-line)
		(and (looking-at "(*")
		     (not (m3::in-comment-or-string))))
	      (m3::indent-to cur-point (m3::indent-for-line)))

	     ;;; Otherwise, indent to same level as previous
	     ;;; non-whitespace line.
	     (t
	      (m3::indent-to
	       cur-point
	       (save-excursion
		 (forward-line -1)
		 (while (looking-at m3::whitespace-line-re)
		   (forward-line -1))
		 (m3::skip-whitespace-in-line)
		 (if (looking-at "(\\*")
		     (progn (forward-char 2)
			    (m3::skip-whitespace-in-line)))
		 (current-column))))))))

     ;; We're not in a comment or a string.  Indent the current line.
     (t
      (m3::indent-to (point) (m3::indent-for-line))
      ;; Do the appropriate thing for electric end's.
      (m3::do-electric-end)))))


(defun m3::indent-for-line ()
  (save-excursion
    (beginning-of-line)
    (let* ((cur-point (point))
	   (part-start (save-excursion
			 (m3::backward-to-last-part-begin)
			 (point)))
	   (first-code
	    (save-excursion
	      (re-search-forward "[ \t]*"
				 (save-excursion (end-of-line) (point))
				 t)
	      (goto-char (match-end 0))
;;;	      (message "first-code 2") (sit-for 2)
	      (point)))
	   (need-keyword
	    (or
	     (save-excursion
	       (goto-char first-code)
	       (looking-at m3::keyword-ssl-enders))
	     (and
	      (save-excursion
		(goto-char part-start)
		(looking-at m3::same-line-ssl-keywords))
	      (save-excursion
		(goto-char first-code)
		(looking-at m3::part-starters)))))
	   (after-keyword nil)		; non-nil indicates that the line
					; used for indentation was not
					; complete, but rather was
					; chose because it started
					; with a keyword.
	   ;; Must do this because Modula is case-sensitive
	   (case-fold-search nil))

      ;; Now figure out if there is an intervening "incomplete
      ;; line" between here and the original line:
      ;; (A complete statement forms a complete line.  Also, a line
      ;; ending in an ssl-introducer forms a complete line.  All other
      ;; lines are incomplete...)
      (let ((prev-statement-start (point)))
;;;	(message "Checking completeness") (sit-for 2)
	(cond
	 ;; Is it incomplete?
	 ((m3::prev-line-incomplete-p cur-point first-code part-start)

	  ;; ...OK, the previous line *was* incomplete.
	  (goto-char cur-point)
;;;	  (message "m3::indent-for-line: incomplete") (sit-for 2)
	  (m3::incomplete-indent cur-point first-code part-start))

	 (t
	  ;; Find beginning of statement upon which to base the
	  ;; indentation of the current line.
;;;	    (message "m3::complete-line-start before") (sit-for 2)
	  (setq after-keyword 
		(m3::backward-to-complete-line-start
		 part-start first-code (if need-keyword 'need)))
;;;	    (message "m3::complete-line-start after") (sit-for 2)

;;;	  (message "m3::indent-for-line: indent, ak = %s" after-keyword)
;;;	  (sit-for 2)
	  (cond
	   (after-keyword
	    (m3::after-keyword-adjust-indent (current-column)
					     first-code part-start))
	   (t
	    (m3::complete-adjust-indent (current-column) first-code
					part-start)))))))))

(defun m3::backward-to-complete-line-start
  (part-start first-code ssl-state)
  "Find beginning of statement upon which to base the indentation of
the line whose first non-blank character is at FIRST-CODE.  If
SSL-STATE is 'need, the keyword at first-code is an ssl-ender,
so we want to find the line that ended with the ssl-introducer that
the ssl-ender ended (whew.)  If Returns t iff the line found starts
with a keyword-statement-starter."

  ;; We must find the first previous line upon which we can base
  ;; the indentation.  Here is the algorithm:
  
  ;; We have set first-code to the character position of the first
  ;;   character in the line to be indented.
  ;;   Search backward for the first end-of-statement or
  ;;     keyword-line-starter.  (An end-of-statement is a
  ;;     semicolon or END; a keyword-line-starter is a keyword
  ;;     that changes the indentation when it starts a line.)
  ;;   end-of-statement was found =>
  ;;     Is there any code between the end-of-statement and
  ;;     first-code?
  ;;     Yes =>
  ;;       Go to the first character of that code and leave the
  ;;       point there.
  ;;     No ==>
  ;;       We don't know how far back this statement begins.
  ;;       If the statement-ender is an END =>
  ;;         Find the end-matcher.
  ;;         If that is a line starter =>
  ;;           Leave the point there.
  ;;         Otherwise =>
  ;;           Recursively go backward-to-complete-line-start.
  ;;       else =>
  ;;         Search backward again for the first end-of-statement,
  ;;         ssl-introducer, or keyword-line-starter.
  ;;         end-of-statement, ssl-introducer found =>
  ;;           forward-to-code; leave point there.
  ;;         keyword-line-starter =>
  ;;           Leave point at the start of the keyword.
  ;;   keyword-line-starter was found =>
  ;;     Leave point at the start of the keyword.

  (let ((after-keyword nil) (in-end-match nil))
;;;    (message "m3::cl-start(A) ps = %d, need = %s" part-start ssl-state)
;;;    (sit-for 2)
    (m3::backward-to-ender-starter-or-ssl-intro part-start)

;;;    (message "m3::indent-for-line(A10)") (sit-for 2)

    (when (looking-at m3::handler-start-re)
      (m3::backward-to-handler-start))

;;;    (message "m3::indent-for-line(A11)") (sit-for 2)


    (cond
     ((looking-at "\\(;\\|\\bEND\\b\\|\\bUNTIL\\b\\)")
      ;;   end-of-statement was found =>
;;;      (message "m3::indent-for-line(A-x1)") (sit-for 2)
      (cond
       ((and (eq ssl-state 'need) (not (looking-at "\\bEND\\b\\|\\bUNTIL\\b")))
;;;	(message "m3::indent-for-line(A-x1-0)") (sit-for 2)
	(setq after-keyword
	      (m3::backward-to-complete-line-start
	       part-start first-code ssl-state)))
       (t
	(let ((ender-start (point)))
;;;	  (message "m3::indent-for-line(A-x2-0)") (sit-for 2)
	  (m3::end-of-ender first-code)
;;;	  (message "m3::indent-for-line(A-x2-1)") (sit-for 2)
	  ;;     Is there any code between the end-of-statement and
	  ;;     first-code?
	  (m3::forward-to-code (point-max))
;;;	  (message "m3::indent-for-line(A-x2)") (sit-for 2)
	  (cond
	   ((< (point) first-code)
	    ;;     Yes =>
	    ;;       Go to the first character of that code and leave the
	    ;;       point there.
;;;	    (message "m3::indent-for-line(A-x2b)") (sit-for 2)
	    (setq after-keyword
		  (looking-at (concat "\\(" m3::keyword-line-starters
				      "\\)"))))
	   (t
;;;	    (message "m3::indent-for-line(A-x2a)") (sit-for 2)
	    ;;     No ==>
	    ;;       We don't know how far back this statement begins.
	    (goto-char ender-start)
;;;	    (message "m3::indent-for-line(A-x2a0)") (sit-for 2)
	    (cond
	     ;;       If the statement ender is an END =>
	     ;;         Find the end-matcher and see if it is a
	     ;;         keyword-line-starter.  If not, search again...
	     ((looking-at "\\(\\bEND\\b\\|\\bUNTIL\\b\\)")
	      (cond
	       ((looking-at "\\bEND\\b")
		(m3::backward-to-end-match part-start))
	       ((looking-at "UNTIL")
		(m3::backward-to-until-match part-start)))
	      (setq in-end-match t)
;;;	      (message "m3::complete-line-start END-match 0") (sit-for 2)
	      (let ((begin-start (point)) (not-begin nil))
		(when (looking-at "BEGIN")
		    ;; If this begin is the main body of a procedure or
		    ;; module, skip back further to the PROCEDURE or
		    ;; MODULE keywords.
		    (m3::backward-to-BEGIN-owner)
		    (if (not (= (point) begin-start)) (setq not-begin t)))
;;;		(message "m3::complete-line-start END-match") (sit-for 2)
		(if (and
		     (looking-at (concat "\\("
					 m3::keyword-line-starters
					 "\\)"))
		     (not (eq ssl-state 'need)))
		    (progn
		      (setq after-keyword not-begin)
;;;		      (message "&&&&") (sit-for 2)
		      )
		  (setq after-keyword
			(m3::backward-to-complete-line-start
			 part-start (point) ssl-state))
;;;		  (message "m3::cl-start END-match recurse returns %s"
;;;			   after-keyword)
;;;		  (sit-for 2)
		  )))

	   ;;       else =>
	     (t
	      ;;         Search backward again for the first end-of-statement,
	      ;;         ssl-introducer, or keyword-line-starter.
	      (setq after-keyword
		    (m3::backward-to-complete-line-start
		     part-start first-code ssl-state))))))))))
	      

     ;;   ssl-introducer was found =>
     ((looking-at
       (concat "\\(" m3::keyword-endable-ssl-introducers "\\)"))
      (let ((ssl-intro-start (point)))
	(cond
	 ((progn
;;;	    (message "m3::c-l-start X -- 1a") (sit-for 2)
	    (re-search-forward
	     (concat "\\(" m3::keyword-endable-ssl-introducers "\\)")
	     first-code)
	    (goto-char (match-end 0))
;;;	    (message "m3::c-l-start X -- 1a2") (sit-for 2)
	    (m3::forward-to-code (point-max))
	    (< (point) first-code))
	  (cond
	   ((eq ssl-state 'need)
;;;	    (message "m3::c-l-start X -- 1b") (sit-for 2)
	    (goto-char ssl-intro-start)
	    (setq after-keyword
		  (save-excursion
		    (goto-char first-code)
		    (not (looking-at m3::part-starters))))
			       
	    (when (not (looking-at
			(concat "\\(" m3::keyword-line-starters "\\)")))
	      (m3::backward-to-complete-line-start
	       part-start (point) nil)))
	   (t
;;;	    (message "m3::c-l-start X -- 1b2") (sit-for 2)
	    (setq after-keyword
		  (looking-at (concat "\\(" m3::keyword-line-starters
				      "\\)"))))))

	 ((progn
	    (goto-char ssl-intro-start)
	    (not (looking-at (concat "\\(" m3::keyword-line-starters "\\)"))))
;;;	  (message "m3::c-l-start Y 1") (sit-for 2)
	  (setq after-keyword t) ;; The ssl-introducer suffices...
	  (m3::backward-to-complete-line-start
	   part-start (point) nil))
	  
	  ;;; must be a keyword-line-starter
	 (t
;;;	  (message "m3::c-l-start Z") (sit-for 2)
	  (setq after-keyword t)))))
      
     ;;   keyword-line-starter was found, or at part-start =>
     ;;     Leave point at the start of the keyword.
     (t
;;;      (message "after keyword.") (sit-for 2)
      (setq after-keyword
	    (looking-at (concat "\\(" m3::keyword-line-starters "\\)")))))

    ;; One final little thing to do:
    ;;  Regular expression search backward matches the shortest match.
    ;;  For the handler-start-re, we can't make sure we got the whole thing,
    ;;  because of the poss-qual-id-re.  So now extend it if necessary.
    (when (looking-at m3::handler-start-re)
      (m3::backward-to-handler-start))

    ;; Now: we should be at the first code of the line, or else we
    ;; have to look again...
    (when (> (save-excursion (m3::backward-to-code part-start) (point))
	     (save-excursion (beginning-of-line 1) (point)))
;;;      (message "not first-code, in-end-match = %s" in-end-match) (sit-for 2)
      ;; If we're currently looking at an ssl-introducer, that cancels the
      ;; need for one...
      (when (and (eq ssl-state 'need)
		 (looking-at (concat "\\(" m3::keyword-endable-ssl-introducers
				     "\\)")))
	(setq ssl-state nil))
      (setq after-keyword
	    (m3::backward-to-complete-line-start part-start (point) ssl-state))
      (if (and in-end-match (not (eq ssl-state 'need)))
	  (setq after-keyword nil)))

;;;    (message "returning after-keyword = %s" after-keyword) (sit-for 2)
    after-keyword))

(defun m3::backward-to-handler-start ()
  ;; Assumes we are looking-at a handler-start; Ensures that point is
  ;; at the start of that handler.
  (let ((new-point (point)))
    ;; First of all, we might not be at the start of the id...
    (while (save-excursion
	     (forward-char -1)
	     (looking-at m3::identifier-char-re))
      (forward-char -1))
    (setq new-point (point))
      
    (save-excursion
      (forward-char -1)
      (cond
       ((looking-at "\\b.")
;;;	(message "m3::backward-to-handler-start A") (sit-for 2)
	(forward-word -1)
	(when (looking-at m3::handler-start-re)
	  (m3::backward-to-handler-start)
	  (setq new-point (point))))

       ((looking-at "[ \t,|]")
;;;	(message "m3::backward-to-handler-start B") (sit-for 2)
	(let ((last-point (point)))
	  (when (and (re-search-backward "[|,][ \t]*" (point-min) t)
		     (equal (match-end 0) last-point))
	    (cond
	     ((looking-at "|")
	      (setq new-point (match-beginning 0)))
	     ((looking-at ",")
	      (forward-word -1)
	      (m3::backward-to-handler-start)
	      (setq new-point (point)))))))))
	    
    (goto-char new-point)))
	      

	  
(defun m3::backward-to-ender-starter-or-ssl-intro (min-point)
  "Moves backwards to the beginning of the first statement ender, that is
semi-colon or END or UNTIL, or starter (m3::keyword-line-starters) or
ssl-introducer, or, if none are found before min-point, to min-point."
;;;  (message "m3::backward-to...0")
  (m3::re-search-backward
   (concat "\\(;\\|\\bEND\\b\\|\\bUNTIL\\b\\|"
	   "^[ \t]*\\(" m3::keyword-line-starters "\\)\\|"
	   m3::keyword-endable-ssl-introducers "\\)")
   min-point 'move-to-point)
;;;    (message "m3::backward-to...0.1") (sit-for 1)
  (while (m3::in-arg-list min-point)
;;;    (message "m3::backward-to...0.5") (sit-for 1)
;;;    (message "m3::backward-to...0.51") (sit-for 1)
    (m3::re-search-backward
     (concat "\\(;\\|\\bEND\\b\\|\\bUNTIL\\b\\|"
	     "^[ \t]*\\(" m3::keyword-line-starters "\\)\\|"
	   m3::keyword-endable-ssl-introducers "\\)")
     min-point t))
;;;  (message "m3::backward-to...1") (sit-for 2)
  (cond
   ((looking-at ";")
    (let ((p (point)))
      (m3::backward-to-code min-point)
      (forward-word -1)
      (if (and (not (looking-at "\\bEND\\b"))
	       (progn (forward-word -1)
		      (not (looking-at "\\bEND\\b"))))
	  (goto-char p))))
   ((looking-at 
     (concat "^[ \t]*\\(" m3::keyword-line-starters "\\)"))
    ;; Must be a keyword-line-starter or ssl-introducer...
;;;    (message "m3::backward-to...2") (sit-for 2)
    (re-search-forward "[ \t]*" (point-max) t))))

(defun m3::end-of-ender (max-point)
  "Assumes point is looking-at END or UNTIL or semi-colon"
  (cond
   ((looking-at "\\bEND\\b")
    (forward-word 1)
    (let ((p (point)))
      (m3::forward-to-code max-point)
      (if (looking-at ";")
	  (forward-char 1)
	(forward-word 1)
	(if (looking-at "[;.]")
	    (forward-char 1)
	  (goto-char p)))))
   ((looking-at "UNTIL")
    (forward-word 1)
    (m3::re-search-forward "\\(;\\|\\bEND\\b\\|\\bUNTIL\\b\\|$\\)"
			   (point-max) 'move-to-limit)
    (cond
     ((looking-at ";") (forward-char 1))
     (t (m3::backward-to-code (point-min)))))
   (t ; semi-colon
    (forward-char 1))))

(defun m3::in-arg-list (part-start)
  "Returns non-NIL iff the point is in a procedure or method argument
list."
;;;  (message "m3::in-arg-list(1)") (sit-for 2)
  (save-excursion
    (let ((cur-point (point)))
      (m3::re-search-backward "PROCEDURE\\|METHODS" part-start t)
      (cond
       ((looking-at "PROCEDURE")
	(forward-word 1)
	(m3::re-search-forward "([^*]" (point-max) t)
;;;	(message "m3::in-arg-list(3)") (sit-for 2)
	(and (< (point) cur-point)
	     (condition-case err
		 (progn
		   (forward-sexp 1)
;;;		   (message "m3::in-arg-list(4)") (sit-for 2)
		   (> (point) cur-point))
	       (error t))))

       ((looking-at "METHODS")
	(let ((continue t) (res nil))
	  (while (and continue (< (point) cur-point))
	    (m3::re-search-forward "([^*]\\|\\bEND\\b" (point-max) t)
;;;	    (message "m3::in-arg-list(101)") (sit-for 2)
	    (cond
	     ((and (looking-at "([^*]") (< (point) cur-point))
;;;	      (message "m3::in-arg-list(101.5)") (sit-for 2)
	      (condition-case err
		  (progn
		    (forward-sexp 1)
;;;		    (message "m3::in-arg-list(102)") (sit-for 2)
		    (if (> (point) cur-point) (setq res t)))
		(error
		 ;; No matching right paren, so must still be in arg list.
;;;		 (message "m3::in-arg-list(103)") (sit-for 2)
		 (setq continue nil)
		 (setq res t))))
	     (t
;;;	      (message "m3::in-arg-list(104)") (sit-for 2)
	      (setq continue nil))))
	  res))

       (t nil)))))
	      

(defun m3::prev-line-incomplete-p (cur-point first-code part-start)
;;;  (message "incomplete?") (sit-for 2)
  (and
   ;; If the last word of the previous line is ";", "END", or an
   ;; ssl-introducer, the previous line is complete.
   (save-excursion
     (goto-char cur-point)
;;;     (message "incomplete: at-cur-point") (sit-for 2)
     (m3::backward-to-code part-start)
;;;     (message "incomplete: at prev-code") (sit-for 2)
     (not (or (and (eq (point) part-start) (looking-at "(*"))
	      (save-excursion
		(and (> (point) 1)
		     (progn (forward-char -1) (looking-at ";"))))
	      (progn (forward-word -1)
		     (looking-at
		      (concat "\\(\\bEND\\b\\|"
			      m3::keyword-endable-ssl-introducers
			      "\\)"))))))
			      
   (or
    ;; Does the previous non-blank line end with an operator?
    (save-excursion
;;;      (message "incomplete-1") (sit-for 2)
      (goto-char cur-point)
      (m3::backward-to-code part-start)
      (or (looking-at "[+\\-*&#<,(]")
	  (and (looking-at ">")
	       (save-excursion
		 (beginning-of-line)
;;;		(message "incomplete-1.1") (sit-for 2)
		 (not (looking-at
		       (concat "[ \t]*"
			       m3::handler-start-re
			       "[ \t]*\\($\\|(\\*\\)")))))
	  (and (looking-at "=")
	       (save-excursion
;;;		(message "incomplete-1.2") (sit-for 2)
		 (beginning-of-line)
;;;		(message "incomplete-1.21") (sit-for 2)
		 (and (not (looking-at
			    (concat "PROCEDURE.*=[ \t]*\\($\\|(\\*\\)")))
		      (not (m3::in-arg-list part-start)))))

	  (and (looking-at ";")
	       (m3::in-arg-list part-start))
		     
	  (and (> (point) 2)
	       (progn
		 (forward-char -2)
		 (or (looking-at
		      (concat m3::not-identifier-char-re "OR"))
		     (and
		      (> (point) 1)
		      (progn
			(forward-char -1)
			(looking-at
			 (concat m3::not-identifier-char-re
				 "\(DIV\\|MOD\\|AND\\|NOT")))))))))

    (save-excursion
      (goto-char cur-point)
      (m3::backward-to-code part-start)
      (and (> (point) part-start)
	   (progn
	     (forward-char 1)
;;;      (message "incomplete-1B1") (sit-for 2)
	     (let ((last-char (point)))
	       (beginning-of-line 1)
	       (and (re-search-forward
		     (concat "^[ \t]*\\(" m3::statement-keywords "\\)")
		     cur-point t)
		    (= last-char (match-end 0)))))))

    (save-excursion
;;;     (message "incomplete-2") (sit-for 2)
      (cond
       ((looking-at "\\bEND;\\b")
;;;       (message "incomplete-2.01") (sit-for 2)
	(forward-char 4))
       ((looking-at
	 (concat "\\bEND[ \t]*" m3::identifier-re "[ \t]*\\(;\\|\\.\\)"))
;;;       (message "incomplete-2.02") (sit-for 2)
	(re-search-forward
	 (concat "\\bEND[ \t]*" m3::identifier-re "[ \t]*\\(;\\|\\.\\)")
	 (point-max) t)
	(goto-char (match-end 0)))
       ((looking-at m3::multi-keyword-line-prefix)
;;;       (message "incomplete-2.1") (sit-for 2)
	(re-search-forward m3::multi-keyword-line-prefix (point-max) t)
	(goto-char (match-end 0)))

       ((looking-at "PROCEDURE")
;;;       (message "incomplete-2.15") (sit-for 2)
	(forward-word 1)
	(m3::re-search-forward "([^*]" (point-max) t)
	(let ((new-point (point)))
	  (save-excursion
	    (condition-case err
		(forward-sexp 1)
	      (error (goto-char (point-max))))
;;;	  (message "incomplete-2.15-2") (sit-for 2)
	    (and (< (point) cur-point)
		 (m3::re-search-forward "=" (point-max) t)
		 (progn
		   (forward-char 1)
		   (and (< (point) cur-point)
;;;		      (message "incomplete-2.15-3") (sit-for 2)
			(setq new-point (point))))))
	  (goto-char new-point)))

       ((looking-at "WITH")
;;;       (message "incomplete-2.191") (sit-for 2)
	(forward-word 1)
	(let ((new-point (point)))
	  (m3::re-search-forward "DO" first-code t)
;;;	 (message "incomplete-2.192") (sit-for 2)
	  (cond
	   ((looking-at "DO")
	    (forward-word 1)
;;;	   (message "incomplete-2.193") (sit-for 2)
	    (setq new-point (point))))
	  (goto-char new-point)))

       ((looking-at "\\bEND\\b")
	(forward-word 1)
	(cond
	 ((save-excursion
	    (m3::forward-to-code (point-max))
	    (looking-at ";"))
	  (m3::forward-to-code (point-max))
	  (forward-char 1))))

       ;; If looking-at keyword-line-starter or part-starter
       ((looking-at (concat m3::keyword-line-starters "\\|" m3::part-starters))
;;;	(message "incomplete-2.2") (sit-for 2)
	(re-search-forward
	 (concat m3::keyword-line-starters "\\|" m3::part-starters)
	 (point-max) t)
	(goto-char (match-end 0)))

       ((looking-at ";")
	(forward-char 1)))

      ;; Go forward to code.
;;;      (message "m3::IFL: before codepoint") (sit-for 2)
      (m3::forward-to-code (point-max))
      ;; Is there something between the last ';' and the current
      ;; line?
;;;     (message "m3::IFL: codepoint") (sit-for 2)
      (and
       (< (point) cur-point)
       ;; Yes -- means that the previous statement was incomplete...

       ;; ...unless the current line is an ssl-ender, in which
       ;; case it is assumed complete...
;;;      (message "incomplete-3") (sit-for 2)
       (or (not
	    (save-excursion
	      (goto-char first-code)
;;;	     (message "incomplete-3.1") (sit-for 2)
	      (looking-at m3::keyword-ssl-enders)))
	   (save-excursion
;;;	    (message "incomplete-3.2") (sit-for 2)
	     (goto-char first-code)
	     (m3::backward-to-code part-start)
	     (forward-char 1)
;;;	    (message "incomplete-3.21") (sit-for 2)
	     (let ((after (point)))
	       (m3::re-search-backward m3::keyword-endable-ssl-introducers
				      part-start t)
	       (re-search-forward m3::keyword-endable-ssl-introducers
				  cur-point t)
	       (goto-char (match-end 0))
;;;	      (message "incomplete-3.22") (sit-for 2)
	       (= (point) after))))

       ;; ... or there is a an ssl-ender between here and first-code
       ;; that is not a semi in an argument list...
       (not (save-excursion
;;;	     (message "incomplete-3.3-0") (sit-for 2)
	      (and (m3::re-search-forward
		    (concat ";\\|" m3::keyword-ssl-enders)
		    first-code 't)
		   (let ((continue t))
		     (while (and continue (m3::in-arg-list part-start))
;;;		      (message "incomplete-3.3-1") (sit-for 2)
		       (re-search-forward
			(concat ";\\|" m3::keyword-ssl-enders)
			first-code 't)
		       (goto-char (match-end 0))
;;;		      (message "incomplete-3.3-2") (sit-for 2)
		       (setq continue
			     (m3::re-search-forward
			      (concat ";\\|" m3::keyword-ssl-enders)
			      first-code 't)))
		     continue)
;;;		  (message "incomplete-3.3") (sit-for 2)
		   (< (point) first-code))))

       ;; ... or the previous statement is a multi-keyword statement
       ;; and the current line is completed by a subsequent keyword...
       (not
	(save-excursion
	  (goto-char cur-point)
	  (m3::backward-to-non-comment-line-start part-start)
;;;	 (message "m3::indent-for-line: multi-keyword") (sit-for 2)
	  (looking-at m3::multi-keyword-lines)))
       )))))



(defun m3::after-keyword-adjust-indent (indent first-code part-start)
  "Point is looking at a keyword at column INDENT; if the current line has
any code it starts at FIRST-CODE.  Return the proper indentation for the
current line."
;;;  (message "m3::after-keyword: indent = %d" indent) (sit-for 2)
  (let ((call-adjust-indent t))
    (cond
     ((looking-at "\\bEND\\b")
;;;      (message "m3::after-keyword(END): i: %d, m3::END: %d, m3::stand: %d"
;;;	       indent m3::END-undent m3::standard-offset)
;;;      (sit-for 2)
      (setq indent (- (+ indent m3::END-undent) m3::standard-offset)))

     ((looking-at "ELSE")
      (setq indent (+ indent m3::ELSE-undent))
      (if (m3::in-case part-start)
	  (setq indent (+ indent m3::case-offset))))
    

     ((looking-at "METHODS")
      (setq indent (+ indent m3::METHODS-undent)))
     ((looking-at "OVERRIDES")
      (setq indent (+ indent m3::OVERRIDES-undent)))
     ((looking-at "EXCEPT\\b")
;;;    (message "m3::after-keyword: EXCEPT" indent) (sit-for 2)
      (setq indent (+ indent m3::EXCEPT-undent)))
     ((looking-at "|")
;;;    (message "m3::after-keyword: vert" indent) (sit-for 2)
      (setq indent (+ indent m3::VERT-undent m3::case-offset)))
     ((looking-at m3::handler-start-re)
;;;      (message "m3::after-keyword: handler-start" indent) (sit-for 2)
      (setq indent (+ indent m3::handler-start-undent m3::case-offset)))
     ((looking-at "FINALLY")
      (setq indent (+ indent m3::FINALLY-undent)))
     ((looking-at "THEN")
      (setq indent (+ indent m3::THEN-undent)))
     ((looking-at "ELSIF")
      (setq indent (+ indent m3::ELSIF-undent)))
     ((looking-at "ELSE")
      (setq indent (+ indent m3::ELSE-undent)))
     ((looking-at "DO")
      (setq indent (+ indent m3::DO-undent)))
     ((looking-at "OF")
      (setq indent (+ indent m3::OF-undent)))
     ((looking-at m3::object-re)
      (setq indent (+ indent m3::OBJECT-undent)))
     ((looking-at "RECORD")
      (setq indent (+ indent m3::RECORD-undent)))

     ;; These are the keywords that can be followed by an SSL that begins on
     ;; the same line -- if so, indent to the level of the first elem.
     ((looking-at m3::same-line-ssl-keywords)
;;;      (message "m3::after-keyword: same-line-ssl") (sit-for 2)
      (let ((eol (save-excursion (end-of-line 1) (point))))
	(save-excursion
	  (forward-word 1)
	  (m3::forward-to-code (point-max))
;;;	  (message "m3::after-keyword: SlSSL(2)") (sit-for 2)
	  (cond
	   ((and
	     m3::follow-continued-indent
;;;	     (progn (message "m3::after-keyword: SlSSL(2.1)") (sit-for 2) t)
	     (<= (point) eol)
;;;	     (progn (message "m3::after-keyword: SlSSL(2.2)") (sit-for 2) t)
	     (save-excursion
	       (goto-char first-code)
	       (not (looking-at (concat m3::part-starters
					"\\|BEGIN\\|\\bEND\\b"))))
;;;	     (progn (message "m3::after-keyword: SlSSL(2.3)") (sit-for 2) t)
	     (save-excursion
	       (goto-char first-code)
	       (m3::backward-to-code part-start)
	       (looking-at ";"))
;;;	     (progn (message "m3::after-keyword: SlSSL(2.4)") (sit-for 2) t)
	     )
;;;	    (message "m3::after-keyword: SLSSL (3)") (sit-for 2)
	    (setq indent (current-column))
	    (setq call-adjust-indent nil))
	   (t
	    (setq indent (+ indent m3::standard-offset)))))))

     ;; These are all the keywords that don't affect the indentation
     ;; when they start complete lines.
     ((looking-at
       (concat "INTERFACE\\|MODULE\\|IMPORT\\|FROM\\|EXCEPTION"))
;;;    (message "m3::after-keyword: no extra") (sit-for 2)
      indent)

     ;; Otherwise, give the standard indentation.
     (t
;;;      (message "m3::after-keyword: standard") (sit-for 2)
      (setq indent (+ indent m3::standard-offset))))
	
    (cond
     (call-adjust-indent
      (save-excursion
	(goto-char first-code)
;;;	(message "m3::after-keyword: calling complete-adjust") (sit-for 2)
	(m3::complete-adjust-indent indent first-code part-start)))
     (t
;;;      (message "m3::after-keyword: not calling complete-adjust") (sit-for 2)
      indent))))


(defun m3::in-case (part-start)
;;;  (message "M3::in-case") (sit-for 2)
  (save-excursion
    (let ((cur-point (point)))
      (m3::backward-to-end-match part-start)
;;;      (message "M3::in-case(2)") (sit-for 2)
      (and
       (looking-at m3::case-starters)
       (progn
	 (cond
	  ((looking-at "TRY")
	   (forward-word 1)
	   ;; Is it a TRY-FINALLY or a TRY-EXCEPT?
	   (let (res (continue t))
	     (while continue
	       (setq res (m3::re-search-forward "TRY\\|EXCEPT\\|FINALLY"
					     cur-point t))
;;;	       (message "M3::in-case(3)") (sit-for 2)
	       (cond
		((looking-at "EXCEPT")
		 (setq continue nil))
		((looking-at "TRY")
		 ;; Go to matching END and try again
		 (m3::forward-to-end-match cur-point))
		(t;; FINALLY or not found
		 (setq res nil)
		 (setq continue nil))))
	     res))
	  (t t)))
       ;;; We are now looking at a case starter.  Make sure there is
       ;;; at least one case arm starter.
       (progn
	 (cond
	  ((looking-at "EXCEPT") (forward-word 1))
	  ((looking-at "CASE\\|TYPECASE")
	   (forward-word 1)
	   (m3::re-search-forward "OF" cur-point 'move-to-limit)
	   (forward-word 1)))
	 (m3::forward-to-code cur-point)
;;;	 (message "M3::in-case: about to test handler") (sit-for 2)   
	 (and (< (point) cur-point)
	      (looking-at m3::handler-start-re)))

;;;       (message "M3::in-case: returning t") (sit-for 2)
       ))))

	 
(defun m3::in-continued-record-def (part-start)
  (if (not (looking-at "\\bEND\\b"))
      (error "m3::in-continued-record-def assumes looking-at END"))
  (save-excursion
    (m3::backward-to-end-match part-start)
    (let ((end-match (point)) (eol (save-excursion (end-of-line) (point))))
      (beginning-of-line)
      (or (save-excursion
	    (re-search-forward "[ \t]*" eol t)
	    (= (point) end-match))
	  (save-excursion
	    (and
	     (re-search-forward "[ \t]*BRANDED[ \t]+" eol t)
	     (= (point) end-match)
	     (save-excursion
	       (goto-char end-match)
	       (looking-at "OBJECT"))))))))

	 
(defun m3::correct-for-trailing-ends (indent part-start)
  ;; If the previous line ends in a (series of) END(s) that does
  ;; (do) not start the line, and are unmatched by the start of the line,
  ;; subtract the END-undent(s) from indent (the Eric Muller convention.)
;;;  (message "correct-for-trailing-ends in: %d" indent) (sit-for 2)
  (let ((prev-line-start
	 (save-excursion
	   (m3::backward-to-code part-start)
	   (beginning-of-line)
	   (m3::forward-to-code (point-max))
;;;	   (message "correct-for-trailing-ends (0)") (sit-for 2)
	   (point))))
    (save-excursion
      (if (save-excursion
	    (m3::backward-to-code part-start)
	    (beginning-of-line)
	    (not (looking-at "[ \t]*END\\b")))
	  (save-excursion
	    (let ((continue t))
	      (while continue
		;; Move back to just after the last "real" (non-";") code
		(m3::backward-to-code part-start)
;;;		(message "correct-for-trailing-ends (1)") (sit-for 2)
		(if (looking-at ";") (m3::backward-to-code part-start))
		(forward-char 1)
;;;		(message "correct-for-trailing-ends (2)") (sit-for 2)
		
		;; Now, what are we looking at?
		(cond
		 ;; Is it an END?
		 ((or (save-excursion
			(forward-word -1) (looking-at "\\bEND\\b"))
		      (save-excursion
			(forward-word -2)
			(looking-at
			 (concat "\\bEND\\b" m3::poss-whitespace-re
				 m3::identifier-re m3::poss-whitespace-re
				 ";"))))
		  ;; Move back to the beginning of the end...
		  (re-search-backward "\\bEND\\b" part-start t)
		  (goto-char (match-beginning 0))
;;;		  (message "correct-for-trailing-ends (3)") (sit-for 2)
		  (if (not (looking-at "\\bEND\\b"))
		      (error "m3::complete-adjust-indent(A)"))
		  ;; Find the end matcher.
		  (let ((em-point
			 (save-excursion
			   (m3::backward-to-end-match part-start)
;;;			   (message "correct-for-trailing-ends EM") (sit-for 2)
			   (point))))
;;;		    (message "xxx") (sit-for 2)
		    (cond
		      ((< em-point prev-line-start)
		       (goto-char prev-line-start)
;;;		       (message "xxx<") (sit-for 2)
		       (setq indent
			     (save-excursion (goto-char em-point)
					     (current-column)))
		       (setq continue nil))
		      ((= em-point prev-line-start)
;;;		       (message "xxx=") (sit-for 2)
		       (setq indent (- indent m3::END-undent))
		       (setq continue nil))
		      ((> em-point prev-line-start)
		       (goto-char em-point)))))
		 (t
		  (setq continue nil))))))))
;;;    (message "m3::trailing-end returns %d" indent) (sit-for 2)
    indent))
     

(defun m3::complete-adjust-indent (indent first-code part-start)
  "Previous statement is complete and starts at column INDENT;
if the current line has any code it starts at FIRST-CODE.  Returns the
proper indentation for the current line."
;;;  (message "m3::complete-adjust(A): indent = %d, first-code = %d"
;;;	   indent first-code)
;;;  (sit-for 2)
  (save-excursion
    (goto-char first-code)
;;;    (message "m3::complete-adjust(B)") (sit-for 2)

    ;; If the previous line ends in a (series of) END(s) that does
    ;; (do) not start the line, and are unmatched before the start of the line,
    ;; add the END-undent(s) (the Eric Muller convention.)
;;;    (setq indent (m3::correct-for-trailing-ends indent part-start))
		  
;;;    (message "yyy2: indent = %d" indent) (sit-for 2)
    (cond
     ;; Some things can only start parts, and must be on the left margin.
     ((looking-at (concat "REVEAL\\b\\|EXCEPTION\\b\\|"
			  "FROM\\b\\|IMPORT\\b"))
      0)
      
     ;; These can start parts, but can also appear in the procedures.
     ((looking-at
       (concat "\\(PROCEDURE\\b\\|CONST\\b\\|VAR\\b\\|TYPE\\b\\|BEGIN\\b\\)"))
      ;; Look backwards for line-beginning-keywords that increase the
      ;; indentation, start an SSL, but don't require an END (i.e.,
      ;; TYPE, VAR, or CONST); or END's.  If the former is found first,
      ;; decrease the indentation to the same as the keyword line's.
      ;; If an END is found whose matcher is not something that can
      ;; occur in a TYPE, VAR, or CONST (i.e. RECORD or OBJECT),
      ;; indent normally.  If neither is found, indent normally.
;;;      (message "yyy7") (sit-for 2)
      (let ((new-indent indent) (continue t))
	(while continue
;;;	  (message "xxx1") (sit-for 2)
	  (m3::re-search-backward
	   (concat "\\(^[ \t]*\\(" m3::same-line-ssl-keywords "\\)\\|"
		   "\\bEND\\b\\|" m3::statement-starters "\\)")
	   part-start 'move-to-limit)
;;;	  (message "xxx2") (sit-for 2)
	  (cond
	   ;; If we reached the part-start because of the move-to-limit,
	   ;; indent to here...
	   ((looking-at (concat "^\\(" m3::part-starters "\\)"))
;;;	    (message "xxx2.5") (sit-for 2)
	    (goto-char first-code)
	    ;; If its the start of a procedure def, indent normally.
	    ;; Otherwise, indent to left margin.
	    (if (not (m3::after-procedure-introducer part-start))
		(setq new-indent 0))
	    (setq continue nil))
	      
	   ((and
	     (looking-at
	      (concat "^[ \t]*\\(" m3::same-line-ssl-keywords "\\)"))
	     (not (m3::in-arg-list part-start)))
	    (setq continue nil)

	    ;;; To accomodate part-starters that establish new indentations,
	    ;;; indent to the level of the previous part-starter, unless
	    ;;; that was a BEGIN.
	    (goto-char first-code)
	    (m3::re-search-backward
	     (concat m3::part-starters "\\|BEGIN") part-start t)
	    (while (m3::in-arg-list part-start)
	      (m3::re-search-backward
	       (concat m3::part-starters "\\|BEGIN") part-start t))
;;;	    (message "xxx3") (sit-for 2)
	    (cond
	     ((looking-at "BEGIN")
	      (setq new-indent (- new-indent m3::standard-offset)))
	     (t
	      (setq new-indent (current-column)))))
	     
	   ((looking-at
	     (concat "\\bEND[ \t]*" m3::identifier-re "[ \t]*;"))
	    (setq continue nil)
	    (setq new-indent (- new-indent m3::standard-offset)))


	   ((looking-at "\\bEND\\b")
	    (m3::backward-to-end-match part-start)
;;;	    (message "xxxEND-match") (sit-for 2)
	    (cond
	     ((looking-at "\\(RECORD\\|OBJECT\\)")
	      nil)
	     (t
	      (setq continue nil))))

	   (t
	    (setq continue nil))))
	new-indent))

     ;; If the current line is an END, add the END-undent.
     ((looking-at "\\bEND\\b")
;;;      (message "zzz1") (sit-for 2)
      (cond
       ((m3::in-case part-start)
	(- indent m3::END-undent m3::case-offset))
       ((save-excursion
	  (m3::backward-to-end-match (point-min))
	  (looking-at "^INTERFACE\\|^MODULE\\|^UNSAFE\\|^GENERIC"))
	0)
       (t
;;;	(message "Subtracting %d from indent %d." m3::END-undent indent)
	(- indent m3::END-undent))))


     ((looking-at "ELSE")
      (- indent m3::ELSE-undent
	 (if (m3::in-case part-start) m3::case-offset 0)))

     ((looking-at "METHODS")
      (- indent m3::METHODS-undent))
     ((looking-at "OVERRIDES")
      (- indent m3::OVERRIDES-undent))
     ((looking-at "EXCEPT")
      (- indent m3::EXCEPT-undent))
     ((looking-at "UNTIL")
      (- indent m3::UNTIL-undent))
     ((looking-at "|")
      (cond
       ((save-excursion
	  (m3::backward-to-code part-start)
;;;	  (message "zzz2") (sit-for 2)
	  (or
	   (save-excursion
	     (and (> (point) 1)
		  (progn (forward-char -1) (looking-at "OF"))))
	   (save-excursion
	     (and (> (point) 5)
		  (progn (forward-char -5) (looking-at "EXCEPT"))))))
	(- indent m3::VERT-undent))
       (t
	(- indent m3::VERT-undent m3::case-offset))))

     ((looking-at "FINALLY")
      (- indent m3::FINALLY-undent))
     ((looking-at "THEN")
      (- indent m3::THEN-undent))
     ((looking-at "ELSIF")
      (- indent m3::ELSIF-undent))
     ((looking-at "ELSE")
      (- indent m3::ELSE-undent))
     ((looking-at "DO")
      (- indent m3::DO-undent))
     ((looking-at "OF")
      (- indent m3::OF-undent))
     ((looking-at "RECORD")
;;;      (message "zzz-record") (sit-for 2)
      (- indent m3::RECORD-undent))
     ((looking-at m3::object-re)
;;;      (message "zzz-object") (sit-for 2)
      (- indent m3::OBJECT-undent))
     (t
;;;      (message "zzz-t: indent = %d" indent) (sit-for 2)
      indent))))
  

(defun m3::incomplete-indent (cur-point first-code part-start)
  (let* (list-indent
	 (prev-line-start
	  (save-excursion
	    (m3::backward-to-non-comment-line-start part-start)
	    (point)))
	 (last-char-prev-line
	  (save-excursion
	    (m3::backward-to-non-comment-line-start part-start)
	    (end-of-line)
	    (m3::backward-to-code
	     (save-excursion (beginning-of-line) (point)))
	    (point)))
	 (prev-line-indent
	  (save-excursion
	    (m3::backward-to-non-comment-line-start part-start)
	    (let ((pli (current-column)))
	      (cond
	       ((looking-at m3::statement-keywords)
		(forward-word 1)
		(m3::forward-to-code first-code)
		(cond
		 ((<= (point) last-char-prev-line)
		  (current-column))
		 (t pli)))
	       (t pli))))))
;;;    (message "m3::incomplete-indent(A)") (sit-for 2)
    (cond
     ;; Did the previous non-blank line end with a paren?
     ((save-excursion
	(goto-char last-char-prev-line)
	(looking-at m3::left-parens))

;;;      (message "m3::incomplete-indent(PAREN)") (sit-for 2)
      ;;   Find the indentation of the previous line,
      ;;     either add open-paren-offset, or indent of paren +
      ;;     open-paren-sep
      (goto-char last-char-prev-line)
      (cond
       (m3::open-paren-offset
;;;	(message "m3::incomplete-indent(PAREN offset)") (sit-for 2)
	(re-search-backward
	 (concat m3::identifier-re m3::poss-whitespace-re)
	 part-start t)
	(goto-char (match-beginning 0))
	;; Account for qualified names.
	(cond
	 ((save-excursion
	    (and (> (point) 1)
		 (progn
		   (forward-char -1)
		   (looking-at "\\."))))
	  (re-search-backward
	   (concat m3::identifier-re m3::poss-whitespace-re)
	   part-start t)
	  (goto-char (match-beginning 0))))

;;;	(message "m3::incomplete-indent(PAREN offset 2)") (sit-for 2)

	(if (and m3::proc-param-from-proc-keyword
		 (save-excursion
		   (forward-word -1)
		   (looking-at "PROCEDURE")))
	    (forward-word -1))

;;;	(message "m3::incomplete-indent(PAREN offset 3)") (sit-for 2)
	(+ (current-column) m3::open-paren-offset))

       (t
	(+ (current-column) m3::open-paren-sep))))
		
     ;; Did the previous line end with a ',' or ';'?:
     ((save-excursion
	(goto-char last-char-prev-line)
	(looking-at ",\\|;"))

;;;      (message "m3::incomplete-indent(COMMA)") (sit-for 2)
      ;; Skip over any matched parens; if this puts us at a line
      ;; containing an unmatched left paren, indent to that +
      ;; paren-sep.  Otherwise, indent same as beginning of that line.
      (save-excursion
	(goto-char last-char-prev-line)
	(let ((continue t) res)
	  (while continue
;;;	    (message "m3::incomplete-indent(COMMA) 0") (sit-for 2)
	    (m3::re-search-backward
	     (concat m3::left-parens "\\|" m3::right-parens)
	     (save-excursion (beginning-of-line)
			     (point)) 'move-to-limit)
;;;	    (message "m3::incomplete-indent(COMMA) 1") (sit-for 2)
	    (cond
	     ((looking-at m3::left-parens)
;;;	      (message "m3::incomplete-indent(COMMA) lp") (sit-for 2)
	      (setq continue nil)
	      (forward-char 1)
	      (re-search-forward "[ \t]*") (goto-char (match-end 0))
	      (setq list-indent (current-column)))
	     ((looking-at m3::right-parens)
;;;	      (message "m3::incomplete-indent(COMMA) rp") (sit-for 2)
	      (forward-char 1)
	      (backward-sexp 1))
	     (t
;;;	      (message "m3::incomplete-indent(COMMA) none") (sit-for 2)
	      (beginning-of-line)
	      (skip-chars-forward "[ \t]") 
	      (setq continue nil)
	      (setq list-indent (current-column)))))
;;;	  (message "m3::incomplete-indent(COMMA) end") (sit-for 2)
	  (cond
	   ((looking-at (concat "|[ \t]*" m3::identifier-char-re))
	    (forward-word 1) (forward-word -1)
	    (setq list-indent (current-column)))
	   ((looking-at m3::statement-keywords)
	    (forward-word 1)
	    (re-search-forward "[ \t]*" last-char-prev-line t)
	    (setq list-indent (current-column))))))
      list-indent)
	      
     ;; Did the previous non-blank line end a procedure header?
     ((m3::after-procedure-introducer part-start)
;;;      (message "m3::incomplete-indent(PROCEDURE)") (sit-for 2)
      (goto-char last-char-prev-line)
      (m3::re-search-backward "PROCEDURE" part-start t)
      (+ (current-column) m3::standard-offset))

     ;; Does the current line start a RAISES clause?
     ((looking-at "^[ \t]*RAISES")
;;;      (message "m3::incomplete-indent(RAISES)") (sit-for 2)
      (goto-char last-char-prev-line)
      (m3::re-search-backward "\\(PROCEDURE\\|METHODS\\)"
			     part-start t)
      (if (looking-at "METHODS")
	  (progn (forward-word 1) (m3::forward-to-code (point-max))))
      (+ (current-column) m3::RAISES-offset))

     ;; Did the previous line end with an assignment?
     ((save-excursion
	(goto-char last-char-prev-line)
	(beginning-of-line)
;;;	(message "m3::incomplete-indent(:= 1)") (sit-for 2)
	(and (m3::re-search-forward ":=" (1+ last-char-prev-line) t)
	     (re-search-forward "[^ \t]" last-char-prev-line t)))
;;;      (message "m3::incomplete-indent(:=)") (sit-for 2)
      (goto-char last-char-prev-line)
      (beginning-of-line)
      (m3::re-search-forward ":=" last-char-prev-line t)
      (forward-char 2)
      (re-search-forward "[ \t]*[^ \t]")
      (+ (- (current-column) 1) m3::assign-offset))

     ;; Otherwise:
     (t
;;;      (message "m3::incomplete-indent(OTHER)") (sit-for 2)
      ;; Find out if the previous line begins the statement.
      (goto-char prev-line-start)
      (m3::re-search-backward
       (concat ";\\|" m3::keyword-line-starters "\\|" m3::part-starters
	       "\\|" m3::statement-keywords)
       part-start t)
      (while (m3::in-arg-list part-start)
	(m3::re-search-backward
	 (concat ";\\|" m3::keyword-line-starters "\\|" m3::part-starters
		 "\\|" m3::statement-keywords)
	 part-start t))
;;;      (message "m3::incomplete-indent(OTHER1)") (sit-for 2)
      (if (or (> (point) part-start)
	      (and (= (point) part-start)
		   (looking-at m3::keyword-endable-ssl-introducers)))
	  (progn
	    (re-search-forward
	     (concat ";\\|" m3::keyword-line-starters "\\|" m3::part-starters
		     "\\|" m3::statement-keywords)
	     cur-point t)
	    (goto-char (match-end 0))))
;;;      (message "m3::incomplete-indent(OTHER1.5)") (sit-for 2)
      (m3::forward-to-code (point-max))
;;;      (message "m3::incomplete-indent(OTHER2), prev-line-start = %d"
;;;	       prev-line-start)
;;;      (sit-for 2)
      (cond
       ;; If the previous line begins the statement, add
       ;; m3::standard-offset to indentation, unless the prev-line-indent
       ;; has already skipped over a keyword.
       ((= (point) prev-line-start)
;;;	(message "m3::incomplete-indent(START): prev-line-indent = %d"
;;;		 prev-line-indent)
;;;	(sit-for 2)
	(m3::complete-adjust-indent
	 ;; Indent further if we haven't indented already.
	 (cond
	  ((= prev-line-indent
	      (save-excursion (goto-char prev-line-start) (current-column)))
	   (+ prev-line-indent m3::continued-line-offset))
	  (t prev-line-indent))
	 first-code part-start))
       (t
;;;	(message "m3::incomplete-indent(CONT)") (sit-for 2)
	;; Otherwise, same indentation as previous, modulo adjustment
	;; for current line
	prev-line-indent))))))


(defun m3::after-procedure-introducer (part-start)
  "Returns t iff first non-blank non-comment character before point is the '='
of a procedure definition."
  (save-excursion
    (m3::backward-to-code part-start)
    (and
     (looking-at "=")
;;;     (message "m3::API(0)") (sit-for 2)
     (let ((eq-point (point)))
       (and
	;; Not that this does not allow any comments in
	;;   PROCEDURE Foo <left-paren>
	;; and all must occur on the same line.
	(m3::re-search-backward
	 (concat "PROCEDURE[ \t]*" m3::identifier-re "[ \t]*(")
	 part-start t)
;;;	(message "m3::API(1)") (sit-for 2)
	(progn
	  (re-search-forward
	   (concat "PROCEDURE[ \t]*" m3::identifier-re "[ \t]*(")
	   eq-point t)
	  (goto-char (match-end 0))
;;;	  (message "m3::API(2)") (sit-for 2)
	  (forward-char -1)
	  (and
	   (condition-case err
	       (progn (forward-sexp 1) t)
	     (error nil))
;;;	   (message "m3::API(3)") (sit-for 2)
	   ;; We should now be at the right paren of the arg-list.
	   ;; Check for a return type.
	   (progn
	     (m3::forward-to-code eq-point)
	     (and
;;;	      (message "m3::API(4)") (sit-for 2)
	      (cond
	       ((looking-at ":")
		(forward-char 1)
		(m3::forward-to-code eq-point)
		(and
		 (looking-at m3::poss-qual-ident-re)
		 (progn
		   (re-search-forward m3::poss-qual-ident-re eq-point t)
		   (goto-char (match-end 0))
		   (m3::forward-to-code eq-point)
		   t)))
	       (t t))
	      ;; Now check for RAISES clause.
;;;	      (message "m3::API(5)") (sit-for 2)
	      (cond
	       ((looking-at "RAISES")
		(forward-word 1)
		(m3::forward-to-code eq-point)
		(cond
		 ((looking-at "ANY")
		  (forward-word 1)
		  (m3::forward-to-code eq-point)
		  t)
		 ((looking-at "{")
;;;		  (message "m3::API(5.5)") (sit-for 2)
		  (and
		   (condition-case err
		       (progn (forward-sexp 1) t)
		     (error nil))
		   (progn (m3::forward-to-code eq-point) t)))
		 (t t)))
	       (t t))

	      ;; Now, we better be back to the original =!
	      (= (point) eq-point))))))))))


(defun m3::backward-to-end-match (part-start &optional depth)
  (if (not depth) (setq depth 0))
  (let (res
	(case-fold-search nil)
	(continue t))
    (while continue
;;;      (message "m3::backward-to-end-match(1) [%d]" depth) (sit-for 1)
      (setq res (m3::re-search-backward
		 (concat "\\(" m3::end-matchers "\\|\\bEND\\b\\)") 
		 part-start t))
      (cond
       ((and res (looking-at "\\bEND\\b"))
	(m3::backward-to-end-match part-start (1+ depth)))
       (t
	(setq continue nil))))
    res))

(defun m3::forward-to-end-match (max-point &optional depth)
  (if (not depth) (setq depth 0))
  (if (looking-at (concat "\\(" m3::statement-starters "\\)")) (forward-word 1)
)
  (let (res
	(case-fold-search nil)
	(continue t))
    (while continue
;;;      (message "m3::backward-to-end-match(1) [%d]" depth) (sit-for 1)
      (setq res (m3::re-search-forward
		 (concat "\\(" m3::statement-starters "\\|\\bEND\\b\\)")
		 max-point t))
      (cond
       ((looking-at m3::statement-starters)
	(m3::forward-to-end-match max-point (1+ depth)))
       (t   ;; looking at END or reached max-point
	(forward-word 1)
	(setq continue nil))))
    res))

(defun m3::backward-to-until-match (part-start &optional depth)
  (if (not depth) (setq depth 0))
  (let (res
	(case-fold-search nil)
	(continue t))
    (while continue
;;;      (message "m3::backward-to-end-match(1) [%d]" depth) (sit-for 1)
      (setq res (m3::re-search-backward
		 (concat "\\(\\bREPEAT\\b\\|\\bUNTIL\\b\\)") part-start t))
      (cond
       ((and res (looking-at "UNTIL"))
	(m3::backward-to-until-match part-start (1+ depth)))
       (t
	(setq continue nil))))
    res))

(defun m3::forward-sexp (n)
  "Moves forward to the (end of the) END that terminates the current innermost
syntactic unit.  With a prefix argument, does that N times."
  (interactive "p")
  (while (and (> n 0) (< (point) (point-max)))
    (m3::forward-to-end-match (point-max))
    (setq n (- n 1))))

(defun m3::backward-sexp (n)
  "Moves backward to the (start of) the keyword that starts the current
innermost syntactic unit.  With a prefix argument, does that N times."
  (interactive "p")
  (while (and (> n 0) (> (point) (point-min)))
    ;; Make forward and backward sexp inverses...
    (forward-word -1)
    (m3::backward-to-end-match (point-min))
    (setq n (- n 1))))

(defun m3::end-of-defun (n)
  "Moves forward to the line after the end of the current 'defun', or top-level
syntactic unit.  With a prefix argument, does that N times."
  (interactive "p")
  (while (and (> n 0) (< (point) (point-max)))
    (m3::end-of-defun-work)
    (setq n (- n 1))))

(defun m3::end-of-defun-work ()
  (skip-chars-forward " \t\n")
  (if (not (looking-at 
	    (concat "^\\(" m3::com-start-re "\\|" m3::part-starters
		    "\\|\\bEND\\b\\)")))
      (m3::backward-to-last-part-begin))
  (cond
   ((looking-at m3::com-start-re)
    (m3::skip-comment-forward (point-max) t)
    (beginning-of-line 2))
   ((looking-at m3::part-starters)
    (forward-char 1)
    (let ((start (point)))
      (if (re-search-forward
	   (concat "^\\(" m3::com-start-re "\\|"
		   m3::part-starters "\\|\\bEND\\b\\)")
	   (point-max) 'move-to-limit)
	  (goto-char (match-beginning 0)))
      (if (looking-at m3::com-start-re) (forward-char -2))
      (m3::backward-to-code start)
      (beginning-of-line 2)))
   (t (beep))))



(defun m3::backward-to-non-comment-line-start (part-start)
  "Sets the point at the first non-whitespace character in a line that
contains something other than comments and/or whitespace."
  (m3::backward-to-code part-start)
  (beginning-of-line)
  (m3::skip-whitespace-in-line))


(defun m3::skip-whitespace-in-line ()
  (re-search-forward "[ \t]*"))


(defun m3::indent-to (cur-point new-column)
  "Make current line indentation NEW-COLUMN.  If the point is to the
left of the first non-blank character, move it to NEW-COLUMN.
Otherwise, maintain its relative position.  Has the side effect
of converting tabs to spaces."
  (goto-char cur-point)
  (untabify (save-excursion (beginning-of-line) (point))
	    (save-excursion (end-of-line) (point)))
  (let ((cur-column (current-column))
	(cur-point (point))
	(first-column
	 (save-excursion
	   (beginning-of-line)
	   (re-search-forward " *")
	   (current-column))))
    (let ((diff (- new-column first-column)))
      (cond
       ((> diff 0)
	(beginning-of-line)
	;; Must do this to make sure the keyword completion marker moves
	;; correctly.
	(let ((d diff))
	  (while (> d 0)
	    (insert-before-markers " ") (setq d (1- d))))
	)
       ((< diff 0)
	(save-excursion
	  (forward-char (- first-column cur-column))
	  (backward-delete-char-untabify (- diff)))))
      (cond
       ((> first-column cur-column)
	(beginning-of-line)
	(forward-char new-column))
       (t
	(goto-char (+ cur-point diff)))))))


(defun m3::in-comment-or-string ()
  "Returns 'string if point is in an unterminated string, 'comment if in
an unterminated comment, otherwise, nil."
  (save-excursion
    (beginning-of-line)
    (let ((cur-point (point))
	  (state nil))
      (save-excursion
	;; We assume the lisp-like convention that "top-level defuns,"
	;; or "parts", are the only things that occur on the left
	;; margin (we make an exception for end-comments.)
	(m3::backward-to-last-part-begin)
	(while (and (not state)
		    (re-search-forward
		     (concat "\\(" m3::com-start-re "\\|\"\\|'\\)")
		     cur-point t))
	  (goto-char (match-beginning 0))
	  (cond
	   ((looking-at m3::com-start-re)
	    (setq state 'comment)
	    (if (m3::skip-comment-forward cur-point t) (setq state nil)))
	   ((looking-at "\"")
	    (setq state 'string)
	    (if (re-search-forward "[^\\\\]\"" cur-point t)
		(setq state nil)))
	   ((looking-at "'")
	    (setq state 'string)
	    (if (re-search-forward "[^\\\\]'" cur-point t)
		(setq state nil)))))
	state))))

(defun m3::backward-to-last-part-begin ()
;;;  (beginning-of-line nil)
;;;  (message "search-start") (sit-for 2)
  (let ((search-start (point)))
    (if (re-search-backward
	 (concat "^\\(" m3::com-start-re "\\|" m3::part-starters
		 "\\|\\bEND\\b\\)")
	 (point-min) t)
	(progn
	  (goto-char (match-beginning 0))
	  (when (looking-at "\\bEND\\b")
	    (m3::end-of-ender (point-max))
	      (forward-line 1) (beginning-of-line 1))
;;;	  (message "prev") (sit-for 2)
	  )
      (goto-char (point-min)))
    (let ((last-found (point)))
      (forward-char 1)
      (if (re-search-forward
	   (concat "^\\(" m3::com-start-re "\\|" m3::part-starters
		   "\\|\\bEND\\b\\)")
	   (point-max) t)
	  (progn
	    (goto-char (match-beginning 0))
	    (when (looking-at "\\bEND\\b")
	      (m3::end-of-ender (point-max))
	      (forward-line 1) (beginning-of-line 1))
;;;	    (message "after-prev") (sit-for 2)
	    )
	(goto-char (point-max)))
      (if (<= search-start (point)) (goto-char last-found))))
;;;  (message "part-start") (sit-for 2)
  )

(defun m3::beginning-of-defun (n)
  "Moves backward to the start of the current 'defun', or top-level
syntactic unit.  With a prefix argument, does that N times."
  (interactive "p")
  (while (and (> n 0) (> (point) (point-min)))
    (forward-char -1)
    (m3::backward-to-last-part-begin)
    (setq n (- n 1))))

  

(defun m3::forward-to-code (max-point)
  "Sets the point at the first non-comment, non-whitespace character
following the current point, else at max-point."
;;;  (message "m3::forward-to-code (1)") (sit-for 2)
  (let ((continue t))
    (while continue
;;;      (message "m3::forward-to-code (1.5)") (sit-for 2)
      (setq continue
	    (and (re-search-forward "[^ \t\n]" max-point 'move-to-limit)
		 (progn (goto-char (match-beginning 0))
;;;			(message "m3::forward-to-code (2)") (sit-for 2)
			(and (looking-at m3::com-start-re)
			     (m3::skip-comment-forward max-point t))))))))


(defun m3::backward-to-code (min-point)
  "Sets the point at the first non-comment, non-whitespace character
before the current point, else at end-of-file"
  (let ((continue t))
    (while continue
      (if (re-search-backward "[^ \t\n][ \t\n]*" min-point t)
	  (goto-char (match-beginning 0))
	(goto-char min-point))
      (setq continue (and (save-excursion
			    (and (> (point) 1)
				 (progn
				   (forward-char -1)
				   (looking-at m3::com-end-re))))
			  (progn
			    (forward-char 1)
			    (m3::skip-comment-backward min-point t)))))

    t))

(defun m3::re-search-forward (re max-point fail)
  "Assumes we're not in a comment or a string.  Puts point at the start of the
first occurence of RE that is not in a comment or string, if such an occurence
occurs before MAX-POINT, and returns non-nil.  Otherwise, returns nil
and leaves point unaffected.  Results are undefined if RE matches any
comment starter."
  (let ((continue t)
	(save-point (point))
	(res nil))
    (while continue
      (setq res (re-search-forward
		  (concat "\\(" m3::com-start-re "\\|\"\\|" re "\\)")
		  max-point fail))
      (goto-char (match-beginning 0))
      (cond
       (res
	(cond
	 ((looking-at m3::com-start-re)
	  (m3::skip-comment-forward max-point fail))
	 ((looking-at "\"")
	  (forward-char -1)
	  (re-search-forward "[^\\]\"" max-point 'move-to-point)
	  (goto-char (match-end 0)))
	 (t
	  (setq continue nil))))
       (t
	(setq continue nil)
	(if (and (eq fail t) (not res))
	    (goto-char save-point)))))
    res))
	

(defun m3::re-search-backward (re min-point fail)
  "Assumes we're not in a comment.  Puts point the start of the
first previous occurence of RE that is not in a comment, if such an occurence
occurs before MIN-POINT, and returns non-nil.  FAIL is interpreted as is third
argument to re-search.  Results are undefined if RE matches any comment
starter." 
  (let ((continue t)
	(save-point (point))
	(res nil))
    (while continue
      (setq res (re-search-backward
		 (concat "\\(" m3::com-end-re "\\|\"\\|" re "\\)")
		 min-point fail))
      (cond
       (res
	(cond
	 ((looking-at m3::com-end-re)
	  (forward-char 2)
	  (m3::skip-comment-backward min-point fail))
	 ((looking-at "\"")
	  (let ((quote-continue t))
	    (while quote-continue
;;;	      (message "m3::re-search-backward (1)") (sit-for 2)
	      (if (re-search-backward "\"" min-point 'move-to-point)
		  (goto-char (match-beginning 0)))
;;;	      (message "m3::re-search-backward (2)") (sit-for 2)
	      (cond
	       ((or (= (point) min-point)
		    (save-excursion
		      (forward-char -1)
		      (not (looking-at "\\\\"))))
		(setq quote-continue nil)))
;;;	      (message "m3::re-search-backward (3)") (sit-for 2)
	      )))
	 (t
	  (setq continue nil))))
       (t
	(setq continue nil)
	(if (and (eq fail t) (not res))
	    (goto-char save-point)))))
    res))

(defun m3::skip-comment-forward (max-point fail)
  "Requires that point is at the start of a comment.  If that comment
is terminated before MAX-POINT, return t and leaves point after end of
the comment.  Otherwise, if fail is 't, returns returns nil and leaves
the point unchanged; if fail is nil raises an errer; if fail is not t or nil,
returns nil and leaves the point at max-point or (point-max), whichever is
smaller."
  (if (not (looking-at m3::com-start-re))
      (error
       "m3::skip-comment-forward should only be called when looking at
comment-starter"))
  (forward-char 2)
  (let ((save-point (point)) (continue t) res)
    (while continue
;;;      (message "m3::comment-forward (0.5)") (sit-for 2)
      (setq res (re-search-forward m3::com-start-or-end-re max-point fail))
      (cond
       (res
;;;	(message "m3::comment-forward (1)") (sit-for 2)
	(goto-char (match-beginning 0))
;;;	(message "m3::comment-forward (2)") (sit-for 2)
	(cond
	 ((looking-at m3::com-start-re)
	  (if (not (m3::skip-comment-forward max-point fail))
	      (progn (setq res nil)
		     (setq continue nil))))
	 ((looking-at m3::com-end-re)
	  (goto-char (match-end 0))
	  (setq continue nil))
	 (t
;;;	  (message "m3::comment-forward (4)") (sit-for 2)
	  (goto-char save-point)
	  (setq res nil)
	  (setq continue nil))))
       (t 
;;;	(message "m3::comment-forward (5)") (sit-for 2)
	(goto-char save-point)
	(setq res nil)
	(setq continue nil))))
    res))


(defun m3::skip-comment-backward (min-point fail)
  "Requires that point is at the end of a comment.  If that comment
is terminated before MIN-POINT, return t and leaves point at the start
the comment.  Otherwise returns nil and leaves the point in an
unspecified position."
  (forward-char -2)
  (if (not (looking-at m3::com-end-re))
      (error
       "m3::skip-comment-backward should only be called when looking at
comment-ender"))
  (let ((save-point (point)) (continue t) res)
    (while continue
      (setq res (re-search-backward m3::com-start-or-end-re min-point fail))
      (cond
       (res
	(cond
	 ((looking-at m3::com-end-re)
	  (forward-char 2)
	  (if (not (m3::skip-comment-backward min-point fail))
	      (progn
		(setq res nil)
		(setq continue nil))))
	 ((looking-at m3::com-start-re)
	  (setq continue nil))
	 (t
	  (goto-char save-point)
	  (setq res nil)
	  (setq continue nil))))
       (t
	(goto-char save-point)
	(setq res nil)
	(setq continue nil))))
    res))
     

;;; -------- Electric END completion --------

(defun m3::do-electric-end ()
;;;  (message "m3::do-electric-end") (sit-for 2)
  (let ((start-point (point))
	(case-fold-search nil))
    (cond
     ((and (save-excursion
	     (end-of-line)
	     (forward-word -1)
;;;	     (progn (message "m3::do-electric-end 1.2") (sit-for 2) t)
	     (and
	      (looking-at "\\bEND\\b")
	      (or (save-excursion (beginning-of-line)
				  (looking-at "[ \t]*\\bEND\\b[ \t]*$"))
		  (progn (forward-word 1)
			 (= (point) start-point)))))
	   (or m3::electric-end m3::blink-end-matchers))
;;;      (progn (message "m3::do-electric-end 1.5") (sit-for 2) t)
      (let ((insert-point
	     (save-excursion (end-of-line)
			     (forward-word -1)
			     (forward-word 1)
			     (point)))
	    (insert-string))
;;;	(progn (message "m3::do-electric-end 2") (sit-for 2) t)
	(end-of-line) (forward-word -1)
	(save-excursion
	  (and
	   (m3::backward-to-end-match (point-min))
	   (if m3::blink-end-matchers (sit-for 1) t)
;;;	   (progn (message "m3::do-electric-end 3") (sit-for 1) t)
	   (progn
	     (cond
	      ;; Do nothing if we're not supposed to...
	      ((not m3::electric-end))
	      ;; If it's a begin, what is it the begin of?
	      ((looking-at "BEGIN")
	       (setq insert-string
		     (save-excursion (m3::backward-to-BEGIN-owner)))
	       )

	      ((looking-at "INTERFACE\\|MODULE")
	       (forward-word 2)
	       (setq insert-string
		     (concat
		      (buffer-substring
		       (save-excursion (forward-word -1) (point))
		       (point))
		      ".")))

	      ;; Otherwise, m3::electric-end must be 'all.
	      ((eq m3::electric-end 'all)
;;;	       (progn (message "m3::do-electric-end non-BEGIN") (sit-for 2) t)
	       (setq insert-string
		     (concat "(* "
			     (buffer-substring
			      (point)
			      (save-excursion (forward-word 1) (point)))
			     " *)")))))))

	(cond
	 (insert-string
	  (progn
	    (goto-char insert-point)
	    ;; If we completed an END and then added something, include
	    ;; the something in the completion...
	    (if (and (marker-position m3::cur-keyword-completion-start)
		     (= insert-point
			(+ m3::cur-keyword-completion-start
			   m3::cur-keyword-completion-len)))
		(setq m3::cur-keyword-completion-len
		      (+ m3::cur-keyword-completion-len 1
			 (length insert-string))))
	    (insert " " insert-string)))
	 (t
	  (goto-char start-point))))))))

(defun m3::backward-to-BEGIN-owner ()
  "Assumes looking-at BEGIN.  If this begin is a module main body or
the body of a procedure, moves backward to the MODULE or PROCEDURE
keyword of that module or procedure, and returns the name of the
MODULE or procedure.  If neither of these are true, does not move
point, and returns the string BEGIN if m3::electric-end is 'all, and
nil otherwise."
;;;  (message "begin-owner") (sit-for 2)
  (let ((insert-string nil) (orig-point (point)) (new-point (point)))
    (save-excursion
      (cond
       ;; If it's on the left margin, it must be a module.
       ((looking-at "^BEGIN")
	(goto-char (point-min))
	(and
	 (re-search-forward "MODULE\\|INTERFACE" (point-max) t)
	 (progn
	   (goto-char (match-beginning 0))
	   (setq new-point (point))
	   (forward-word 2)
	   (setq insert-string
		 (concat
		  (buffer-substring
		   (save-excursion (forward-word -1) (point))
		   (point))
		  ".")))))
       ;; Is it the body of a procedure?
       ((let ((continue t))
	  (while continue
	    (m3::re-search-backward
	     "BEGIN\\|PROCEDURE\\|\\bEND\\b" (point-min) t)
	    (cond
	     ((looking-at "\\bEND\\b")
	      (m3::backward-to-end-match (point-min))
	      (cond
	       ((looking-at "BEGIN")
		(m3::re-search-backward
		 "BEGIN\\|PROCEDURE" (point-min) t)
		(if (looking-at "BEGIN") (forward-word 1)))))
	     (t
	      (setq continue nil))))
	  (and (looking-at "PROCEDURE")
	       (progn
;;;		 (message "m3::BEGIN-owner PROC 2") (sit-for 2)
		 (setq new-point (point))
		 (forward-word 2)
		 (setq insert-string
		       (concat
			(buffer-substring
			 (save-excursion (forward-word -1) (point))
			 (point))
			";"))))))
       ;; Otherwise, it is just a random BEGIN, so
       ;; m3::electric-end must be 'all.
       ((eq m3::electric-end 'all)
	(setq insert-string "(* BEGIN *)"))))
    (goto-char new-point)
    insert-string))
	  

;;;  --------  PSEUDO ABBREV MODE --------

(defun m3::toggle-abbrev ()
  "Toggle the flag enabling/disabling Modula 3 pseudo abbrev mode."
  (interactive)
  (setq m3::abbrev-enabled (not  m3::abbrev-enabled))
  (message "M3 abbrev-enabled is now %s." 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)
  "Returns non-nil if WORD is abbreviation of given KEYWORD."
  (if (> (length word) (length keyword)) ()
    (string-equal (substring keyword 0 (length word)) (upcase word))))


(defun m3::is-prefix (word prefix &optional no-upper)
  "returns non-nil if PREFIX is a (non-proper) prefix of WORD."
  (let ((uword (if no-upper word (upcase word)))
	(uprefix (if no-upper prefix (upcase prefix))))
    (if (> (length prefix) (length word)) nil
      (string-equal (substring uword 0 (length prefix)) uprefix))))


(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)) ()
    (forward-word -1)
    (delete-region (point) (save-excursion (forward-word 1) (point)))
    t))
		 

(defun m3::complete-abbrev ()
  "call appropriate m3::function depending on value of last word in buffer."
  (let ((pw (m3::prev-word)))
    ;; Must split this in two because it's so big (or else elisp
    ;; can't handle it.)
    (if m3::abbrev-enabled
	(m3::complete-abbrev-work pw))))
      

;;; Here is the data structure we use to decide what keywords are
;;; appropriate completions of a prefix in the current context, and
;;; how we should order them.
;;;
;;; This alist associates with each keyword:
;;; (<score> <left-margin> <pred>)
;;;
;;; <score> is a score for breaking ties.  Smaller numbers are
;;;    preferred to higher.
;;; <props> is a list of properties of the keyword.
;;;    Properties include:
;;;      left-margin status:  It is assumed that a keyword cannot
;;;        appear at the left-margin unless it has one of the
;;;        properties 'lm-ok or 'lm-only, which indicate that it can
;;;        or must appear at the left margin, respectively.
;;;      line-starter status:  It is assumed that a keyword cannot
;;;        appear after an ssl-introducer unless it has one of the
;;;        properties 'ls-ok or 'ls-only, which indicate that it can
;;;        or must appear after an ssl-introducer, respectively.
;;; <pred>, if non-nil, is a function that must return non-nil for the
;;;    completion to be legal

(defconst m3::keyword-completions
  '(("ABS" . (3 ()))
    ("ADDRESS" . (5 ()))
    ("ADR" . (6 ()))
    ("ADRSIZE" . (7 ()))
    ("AND" . (2 ()))
    ("ANY" . (1 () (lambda (on-lm starts-ssl)
		     (m3::keyword-before-ssl-introducer-p "RAISES"))))
    ("ARRAY" . (4 (ls-ok) (lambda (on-lm starts-ssl)
			    (or (not starts-ssl)
				(save-excursion
				  (forward-word -2)
				  (looking-at "OF"))))))

    ("BEGIN" . (1 (lm-ok ls-ok) (lambda (on-lm starts-ssl)
				    (save-excursion
				      (forward-word -1)
				      (if (not starts-ssl)
					  (m3::after-procedure-introducer
					   (point-min))
					t)))))
    ("BITS" . (6 ()))
    ("BITSIZE" . (7 ()))
    ("BOOLEAN" . (3 ()))
    ("BRANDED" . (4 ()))
    ("BY" . (2 () (lambda (on-lm starts-ssl)
		    (m3::keyword-before-ssl-introducer-p "FOR"))))
    ("BYTESIZE" . (5 ()))

    ("CARDINAL" . (4 (ls-of)))
    ("CASE" . (3 (ls-only)))
    ("CEILING" . (5 ()))
    ("CHAR" . (2 (ls-of)))
    ("CONST" . (1 (lm-ok ls-ok)))

    ("DEC" . (2 (ls-only)))
    ("DISPOSE" . (4 (ls-only)))
    ("DIV" . (3 ()))
    ("DO" . (1 () (lambda (on-lm starts-ssl)
		    (save-excursion
		      (forward-word -1)
		      (or
		       (m3::keyword-before-ssl-introducer-p "WHILE")
		       (m3::keyword-before-ssl-introducer-p "WITH")
		       (m3::keyword-before-ssl-introducer-p "FOR")
		       (m3::keyword-before-ssl-introducer-p "LOCK"))))))

    ("ELSE" . (2 (ls-ok) (lambda (on-lm starts-ssl)
			   (or (m3::end-matcher-is-p "IF")
			       (m3::end-matcher-is-p "TRY")
			       (m3::end-matcher-is-p "\\bCASE")
			       (m3::end-matcher-is-p "\\bTYPECASE")))))
    ("ELSIF" . (3 (ls-ok) (lambda (on-lm starts-ssl)
			    (m3::end-matcher-is-p "IF"))))
    ("END" . (1 (lm-ok ls-ok)))
    ("EVAL" . (7 (ls-only)))
    ("EXCEPT" . (6 (ls-ok) (lambda (on-lm starts-ssl)
			     (m3::end-matcher-is-p "TRY"))))
    ("EXCEPTION" . (5 (lm-only ls-ok)))
    ("EXIT" . (8 (ls-only)))
    ("EXPORTS"  . (4 () (lambda (on-lm starts-ssl)
			  (save-excursion
			    ;; One for prefix of EXPORTS one for module name,
			    ;; one for MODULE.
			    (forward-word -3)
			    (looking-at "MODULE")))))

    ("FALSE" . (4 ()))
    ("FINALLY" . (3 (ls-ok) (lambda (on-lm starts-ssl)
			      (m3::end-matcher-is-p "TRY"))))
    ("FIRST" . (5 ()))
    ("FLOAT" . (6 ()))
    ("FLOOR" . (7 ()))
    ("FOR" . (2 (ls-ok)))
    ("FROM" . (1 (lm-only ls-ok)))

    ("GENERIC" . (1 (lm-only)))

    ("IMPORT"  . (2 (lm-ok ls-ok)
		    (lambda (on-lm starts-ssl)
		      (or on-lm
			  (save-excursion
			    (forward-word -3)
			    (looking-at "\\bFROM\\b"))))))
    ("IF" . (3 (ls-only)
	       (lambda (on-lm starts-ssl)
		 (or (not starts-ssl)
		     (save-excursion
		       (forward-word -3)
		       (not (looking-at "\\(\\bARRAY\\|\bSET\\)[ \t]+OF")))))))
    ("IN" . (7 ()))
    ("INC" . (4 (ls-only)
		(lambda (on-lm starts-ssl)
		  (or (not starts-ssl)
		      (save-excursion
			(forward-word -3)
			(not (looking-at
			      "\\(\\bARRAY\\|\bSET\\)[ \t]+OF")))))))
    ("INTEGER" . (5 (ls-ok)
		    (lambda (on-lm starts-ssl)
		      (or (not starts-ssl)
			  (save-excursion
			    (forward-word -2)
			    (looking-at "OF"))))))
    ("INTERFACE" . (1 (lm-ok) (lambda (on-lm starts-ssl)
				(save-excursion
				  (or on-lm
				      (progn
					(forward-word -2)
					(and
					 (m3::at-left-margin-p)
					 (looking-at "GENERIC\\|UNSAFE"))))))))
    ("ISTYPE" . (7 ()))

    ("LAST" . (3 ()))
    ("LOCK" . (1 (ls-only)
		 (lambda (on-lm starts-ssl)
		   (save-excursion (forward-word -2)
				   (not (looking-at "OF"))))))
    ("LOOP" . (2 (ls-only)
		 (lambda (on-lm starts-ssl)
		   (save-excursion (forward-word -2)
				   (not (looking-at "OF"))))))
    ("LONGFLOAT" . (4 ()))
    ("LONGREAL" . (5 (ls-of)))
    ("LOOPHOLE" . (6 ()))

    ("MAX" . (5 ()))
    ("METHODS" . (2 (ls-only)))
    ("MIN" . (4 ()))
    ("MOD" . (3 ()))
    ("MODULE" . (1 (lm-ok)
		   (lambda (on-lm starts-ssl)
		     (save-excursion
		       (forward-word -1)
		       (or (m3::at-left-margin-p)
			   (progn
			     (forward-word -1)
			     (and (m3::at-left-margin-p)
				  (looking-at "GENERIC\\|UNSAFE"))))))))

    ("NARROW" . (1 ()))
    ("NEW" . (2 ()))
    ("NIL" . (3 ()))
    ("NULL" . (6 ()))
    ("NUMBER" . (5 ()))
    ("NOT" . (4 ()))

    ("OBJECT" . (2 ()
		   (lambda (on-lm starts-ssl)
		     (save-excursion
		       (m3::re-search-backward m3::part-starters (point-min) t)
		       (looking-at "TYPE\\|REVEAL")))))
    ("OF" . (1 () (lambda (on-lm starts-ssl)
		    (or (m3::keyword-before-ssl-introducer-p
			 "\\bCASE\\|\\bTYPECASE")
			(m3::keyword-before-ssl-introducer-p
			 "\\bARRAY\\|SET\\b")))))
    ("OR" . (4 ()))
    ("ORD" . (5 ()))
    ("OVERRIDES" . (3 (ls-only)))

    ("PROCEDURE" . (1 (lm-ok ls-ok)))

    ("RAISE" . (5 (ls-only)))
    ("RAISES" . (3 () m3::raises-ok))
    ("READONLY" . (4 (ls-ok) (lambda (on-lm starts-ssl)
			  (m3::in-arg-list 0))))
    ("REAL" . (9 (ls-of)))
    ("RECORD" . (6 ()))
    ("REF" . (7 ()))
    ("REFANY" . (8 ()))
    ("REPEAT" . (10 (ls-only)))
    ("RETURN" . (2 (ls-only)))
    ("REVEAL" . (1 (lm-only ls-ok)))
    ("ROOT" . (11 ()))
    ("ROUND" . (12 ()))

    ("SET" . (1 ()))
    ("SUBARRAY" . (2 (ls-ok)))

    ("TEXT" . (6 (ls-of)))
    ("THEN" . (1 () (lambda (on-lm starts-ssl)
		      (or (m3::keyword-before-ssl-introducer-p "\\bIF")
			  (m3::keyword-before-ssl-introducer-p "\\bELSIF")))))
    ("TO" . (2 () (lambda (on-lm starts-ssl)
		    (m3::keyword-before-ssl-introducer-p "\\bFOR"))))
    ("TRUE" . (8 ()))
    ("TRUNC" . (9 ()))
    ("TRY" . (3 (ls-only)))
    ("TYPE" . (4 (lm-ok ls-ok)))
    ("TYPECASE" . (5 (ls-only)))
    ("TYPECODE" . (7 ()))

    ("UNSAFE" . (1 (lm-only)))
    ("UNTIL" . (2 (ls-ok)))
    ("UNTRACED" . (3 ()))

    ("VAL" . (2 () (lambda (on-lm starts-ssl)
		     (and (not (save-excursion
				 (forward-word -1)
				 (m3::after-procedure-introducer 0)))
			  (not (m3::in-arg-list 0))))))

    ("VALUE" . (3 ()
		  (lambda (on-lm starts-ssl)
		    (not (save-excursion
			   (forward-word -1)
			   (m3::after-procedure-introducer 0))))))

    ("VAR" . (1 (lm-ok ls-ok)
		(lambda (on-lm starts-ssl)
		  (or on-lm starts-ssl
		      (save-excursion
			(forward-word -1)
			(m3::after-procedure-introducer 0))
		      (m3::in-arg-list 0)))))

    ("WHILE" . (1 (ls-only)))
    ("WITH" . (2 (ls-only)))))



(defun m3::at-left-margin-p () (eq (current-column) 0))

(defun m3::keyword-before-ssl-introducer-p (keyword)
  "Returns non-nil if KEYWORD occurs before an ssl-introducer (other than
KEYWORD), looking backward."
  (save-excursion
    (m3::re-search-backward
     (concat "\\(;\\|\\bEND\\b\\|" m3::keyword-endable-ssl-introducers "\\|"
	     keyword "\\)")
     (point-min) 't)
    (looking-at keyword)))
      
(defun m3::end-matcher-is-p (keyword)
  "Returns non-nil if the keyword that would match an END inserted at
point is KEYWORD."
  (save-excursion
    (m3::backward-to-end-match (point-min))
    (looking-at keyword)))

(defun m3::raises-ok (on-lm starts-ssl)
  (save-excursion
    (forward-word -1)
    (let ((save-point (point)))
      (and
       (m3::re-search-backward "[^*])" 0 t)
       (progn
	 (forward-char 1)
	 (and
	  (m3::in-arg-list 0)
	  (progn
	    (forward-char 1)
	    (let ((retval-pat
		   (concat "[ \t\n]*:[ \t\n]*" m3::poss-qual-ident-re)))
	      (if (looking-at retval-pat)
		  (progn
		    (re-search-forward retval-pat)
		    (goto-char (match-end 0))))
	      (m3::forward-to-code (point-max))
	      (= (point) save-point)))))))))
	    

(defun m3::complete-abbrev-work (pw)
;;;  (message "In m3::polite-abbrev") (sit-for 2)
  (let ((case-fold-search nil))
    (cond
     ;; First, if the start of the current keyword is the same as the
     ;; start of the last keyword we completed, and the user hasn't
     ;; appended any characters, and m3::cur-keyword-completions is non-nil,
     ;; try the next completion in the list.
     ((and
;;;     (progn (message "In m3::polite-abbrev (x1)") (sit-for 2) t)
       (marker-position m3::cur-keyword-completion-start)
;;;     (progn (message "In m3::polite-abbrev (x2)") (sit-for 2) t)
       (> (point) m3::cur-keyword-completion-len)
       (= m3::cur-keyword-completion-start
	  (save-excursion
	    (forward-char (- m3::cur-keyword-completion-len))
	    (point)))
;;;     (progn (message "In m3::polite-abbrev (x3)") (sit-for 2) t)
       m3::cur-keyword-completions
       (string-equal (buffer-substring
		      (marker-position m3::cur-keyword-completion-start)
		      (point))
		     (car m3::cur-keyword-completions)))
      (let ((cur-completion (car m3::cur-keyword-completions)))
	(setq m3::cur-keyword-completions
	      (append (cdr m3::cur-keyword-completions) (list cur-completion)))
;;;      (progn (message "In m3::polite-abbrev (xx1)") (sit-for 2) t)
	(forward-word -1)
	(delete-region m3::cur-keyword-completion-start
		       (+ m3::cur-keyword-completion-start
			  m3::cur-keyword-completion-len))
;;;      (progn (message "In m3::polite-abbrev (xx2)") (sit-for 2) t)
	(insert (car m3::cur-keyword-completions))
	(setq m3::cur-keyword-completion-len
	      (- (point) m3::cur-keyword-completion-start))
	(if (> (length m3::cur-keyword-completions) 1)
	    (message "Other matches: %s"
		     (mapconcat '(lambda (x) x)
				(cdr m3::cur-keyword-completions) ", ")))))

     ;; Otherwise, form the list of (<keyword> . <score>) pairs such
     ;; that pw is a prefix of <keyword>, <score> is the score
     ;; associated with <keyword> in m3::keyword-completions, and the
     ;; conditions in m3::keyword-completions are met.
     (t
;;;    (message "In m3::polite-abbrev (t)") (sit-for 2)
      (let ((keyword-list m3::keyword-completions)
	    matches
	    (on-lm
	     (and
	      (= (save-excursion (forward-word -1) (current-column))
		 0)
	      (let ((continue t) (res nil))
		(save-excursion
;;;		  (message "Checking on-lm, about to enter loop") (sit-for 2)
		  (while continue
		    (setq continue nil)
;;;		    (message "Checking on-lm, before search") (sit-for 2)
		    (m3::re-search-backward
		     (concat m3::part-starters "\\|" m3::end-matchers "\\|"
			     "\\bEND\\b")
		     (point-min) 'move-to-limit)
;;;		    (message "Checking on-lm, after search") (sit-for 2)
		    (cond
		     ((looking-at "\\bEND\\b")
		      (m3::backward-to-end-match (point-min))
		      (if (and (looking-at "BEGIN")
			       (not (looking-at "^BEGIN")))
			  (progn
;;;			    (message "Checking doing BEGIN adjustment")
;;;			    (sit-for 2)
			    (m3::re-search-backward
			     "\\(^PROCEDURE\\|^[ \t]+BEGIN\\)"
			     (point-min) 'move-to-limit)
			    (goto-char (match-end 0))))
		      (setq continue t))
		     ((looking-at (concat "^\\(" m3::part-starters "\\)"))
		      (setq res t))
		     ((looking-at "IMPORT")
		      (save-excursion
			(forward-word -2)
;;;			(message "Doing FROM ... IMPORT special") (sit-for 2)
			(if (looking-at "^FROM")
			    (setq res t))))
		     ((= (point) (point-min))
		      (setq res t)))))
;;;		(message "After loop, res is %s" res) (sit-for 2)
		(and res
		     (save-excursion
		       (forward-word -1)
		       (m3::backward-to-code (point-min))
		       (or (= (point) (point-min))
;;;			   (progn (message "xxx") (sit-for 2) nil)
			   (looking-at ";")))))))
	    (starts-ssl
	     (let ((first-char (save-excursion (forward-word -1) (point))))
	       (save-excursion
		 (forward-word -1)
		 (m3::re-search-backward
		  (concat
		   "\\(;\\|\\bEND\\b\\|"
		   m3::keyword-endable-ssl-introducers "\\)")
		  (point-min) 'move-to-limit)
		 (re-search-forward
		  (concat
		   "\\(;\\|\\bEND\\b\\|"
		   m3::keyword-endable-ssl-introducers "\\)")
		  first-char t)
		 (goto-char (match-end 0))
;;;	       (message "In m3::polite-abbrev (zz1)") (sit-for 2)
		 (m3::forward-to-code (point-max))
		 (= (point) first-char))))
	    (after-of
	     (save-excursion (forward-word -2) (looking-at "OF"))))
;;;	(message
;;;	 "In m3::polite-abbrev, on-lm = %s, starts-ssl = %s, after-of = %s."
;;;	 on-lm starts-ssl after-of)
;;;	(sit-for 2)

	(while keyword-list
	  (let* ((entry (car keyword-list))
		 (kw (car entry)))
;;;	  (message "In m3::polite-abbrev kw = %s" kw) (sit-for 2)
;;;	  (message "Foo") (sit-for 2)
	    (if (m3::is-prefix kw pw)
		(let* ((rest (cdr entry))
		       (score (car rest))
		       (props (car (cdr rest)))
		       (pred (car (cdr (cdr rest)))))
;;;		  (message "In m3::polite-abbrev, found kw = %s" kw) (sit-for 1
)
		  (let ((lm-status
			 (cond
			  ((and (memq 'lm-ok props) (memq 'lm-only props))
			   (error "Bad prop-list in m3::keyword-completions."))
			  ((memq 'lm-ok props) 'lm-ok)
			  ((memq 'lm-only props) 'lm-only)
			  (t 'lm-not)))
			(ls-status
			 (cond
			  ((let ((n 0))
			     (if (memq 'ls-ok props) (setq n (+ n 1)))
			     (if (memq 'ls-only props) (setq n (+ n 1)))
			     (if (memq 'ls-of props) (setq n (+ n 1)))
			     (> n 1))
			   (error "Bad prop-list in m3::keyword-completions."))
			  ((memq 'ls-ok props) 'ls-ok)
			  ((memq 'ls-only props) 'ls-only)
			  ((memq 'ls-of props) 'ls-of)
			  (t 'ls-not))))
;;;		    (message
;;;		     "In m3::polite-abbrev, (2) lm-status = %s ls-status = %s"
;;;		     lm-status ls-status)
;;;		    (sit-for 2)
		    (and
		     (or (eq lm-status 'lm-ok)
			 (cond
			  ((eq lm-status 'lm-only) on-lm)
			  ((eq lm-status 'lm-not) (not on-lm))))
		     (or
;;;		    (progn (message "In m3::polite-abbrev, (3.2)")
;;;			   (sit-for 2) nil)
		      (and (eq ls-status 'ls-ok) (not after-of))
		      (cond
		       ((eq ls-status 'ls-only) (and starts-ssl (not after-of))
)
		       ((eq ls-status 'ls-not) (not starts-ssl))
		       ((eq ls-status 'ls-of) (or (not starts-ssl) after-of))))

		     (or 
;;;		    (progn (message "In m3::polite-abbrev, (5), pred = %s" pred
)
;;;			   (sit-for 2) nil)
		      (not pred)
;;;		    (progn (message "In m3::polite-abbrev, (5)")
;;;			   (sit-for 2) nil)
		      (funcall pred on-lm starts-ssl))
;;;		   (message "In m3::polite abbrev, adding %s to matches" kw)
;;;		   (sit-for 2)
		     (setq matches (cons (cons kw score) matches)))))))
	  (setq keyword-list (cdr keyword-list)))

;;;   (message "In m3::polite-abbrev (after matches): %s" matches) (sit-for 4)
	;; If there are any matches, do a completion
	(and matches
	     (progn
	       ;; Now sort matches according to score.
;;;	     (message "In m3::polite-abbrev, (10)") (sit-for 2)
	       (setq matches
		     (sort matches '(lambda (e1 e2) (< (cdr e1) (cdr e2)))))
	       ;; And strip off the scores from the result.
;;;	     (message "In m3::polite-abbrev, (11)") (sit-for 2)
	       (setq matches (mapcar'(lambda (e) (car e)) matches))
;;;	     (message "In m3::polite-abbrev, (12)") (sit-for 2)
	       (setq m3::cur-keyword-completions matches)
	       (let ((first-match (car matches)))
		 (forward-word -1)
		 (delete-region (point)
				(save-excursion (forward-word 1) (point)))
;;;	       (message "In m3::polite-abbrev, (13)") (sit-for 2)
		 (set-marker m3::cur-keyword-completion-start (point))
		 (insert first-match)
		 (setq m3::cur-keyword-completion-len
		       (- (point) m3::cur-keyword-completion-start))
		 (if (> (length matches) 1)
		     (message
		      "Other matches: %s"
		      (mapconcat '(lambda (x) x) (cdr matches) ", ")))))
	     ))))))


;;;======================================================================

(defun m3::is-letter (ch)
  "checks if argument is a letter."
  (and (>= (upcase ch) ?A) (<= (upcase ch) ?Z)))

(defun m3::abbrev-and-or-indent ()
  "If preceding char in buffer is letter, tries to expand abbrev.
Otherwise, indents the current line."
  (interactive)
;;;  (message "Foo1") (sit-for 2)
  (if (and m3::abbrev-enabled
	   (or (m3::is-letter (preceding-char))
	       (save-excursion
		 (and
		  (> (point) 2)
		  (progn
		    (forward-char -2)
		    (and
		     (looking-at "*)")
		     (progn (forward-word -1) (forward-char -3)
			    (looking-at "(*"))
		     (progn (forward-word -1) (looking-at "\\bEND\\b"))))))
	       (save-excursion
		 (and
		  (> (point) 2)
		  (progn
		    (forward-char -1)
		    (and
		     (looking-at ";\\|.")
		     (progn (forward-word -2) (looking-at "\\bEND\\b")))))))
	   (or (eq (point) (point-max))
	       (eq (following-char) ?\ )
	       (eq (following-char) ?\t)
	       (eq (following-char) ?\n)))
      (progn (m3::complete-abbrev)
	     (m3::indent-line))
    (m3::indent-line)))


;;; ----------------- M3PP pretty printing ------------------

(defvar m3::pp-options '("-ZZ")
  "Command line options that should be passed to m3pp when it is started up.")

(defvar m3::pp-modunit "\002")
(defvar m3::pp-defunit "\005")
(defvar m3::pp-endunit "\001")

(defvar m3::pp-process nil)
(defvar m3::pp-in-progress nil)

(defvar m3::pp-unit-boundary
      (concat "^[ \t]*\nCONST\\|" 
              "^[ \t]*\nTYPE\\|"
              "^[ \t]*\nVAR\\|"
              "^[ \t]*\nPROCEDURE\\|"
              "^[ \t]*\nEXCEPTION\\|"
	      "^[ \t]*\n<\*EXTERNAL\*>|"
	      "^[ \t]*\n<\*INLINE\*>|"
              "^[ \t]*\nMODULE\\|"
	      "^[ \t]*\nINTERFACE\\|"
	      "^[ \t]*\nIMPORT\\|"
              "^[ \t]*\nBEGIN"))

(defun m3::pp-startup ()
  (if (not (and m3::pp-process
		(process-status (process-name m3::pp-process))))
      (save-excursion 
	(get-buffer-create "m3::pp")
	(set-buffer "m3::pp")
	(erase-buffer)
	(setq m3::pp-process 
	      (apply 'start-process "m3::pp" nil "m3pp" m3::pp-options))
	(process-kill-without-query m3::pp-process)
	(set-process-filter m3::pp-process 'm3::pp-filter)
	(process-send-string m3::pp-process 
			     (concat m3::pp-modunit m3::pp-endunit "\n"))
	(accept-process-output m3::pp-process))))

(defun m3::pp-buffer ()
  (interactive)
  (m3::pp-region-safe (point-min) (point-max) (point)))

(defun m3::pp-unit ()
  "Pretty prints the 'unit' containing the cursor. 
   A unit starts with a blank line followed by CONST, TYPE, VAR, 
   PROCEDURE, EXCEPTION, IMPORT, FROM, MODULE, or BEGIN, and it extends 
   to the start of the next unit.  If there is no such unit around the
   cursor, the entire file is pretty printed."
  (interactive)
  (let ((return-point (point)) start end)
    (save-excursion
      (if (not (looking-at
		(concat "^\\(" m3::part-starters "\\)")))
	  (m3::beginning-of-defun 1))
      (setq start (point))
;;;      (message "Unit start...") (sit-for 2)
      (m3::end-of-defun 1)
;;;      (message "Unit end.") (sit-for 2)
      (setq end (point)))
    (m3::pp-region-safe start end return-point)))

(defun m3::pp-region ()
  "Pretty prints the region. 
   The region should consist of zero or more declarations, definitions, 
   import statements, or modules."
  (interactive)
  (m3::pp-region-safe (min (point) (mark)) (max (point) (mark)) (point)))


(defun m3::pp-region-safe (start end return-point)
;;;  (message "m3::pp-region-safe (1) rt = %d" return-point) (sit-for 2)
  (let ((m3pp-type nil)
	(m3pp-start nil))
    (m3::pp-startup)
;;;    (message "m3::pp-region-safe (2)") (sit-for 2)
    (save-excursion
      (goto-char (point-min))
      (if (search-forward m3::pp-endunit (point-max) t)
	  (error "m3pp: file mustn't contain ^A"))
      (get-buffer-create "m3::pp-output")
      (set-buffer "m3::pp-output")
      (erase-buffer))
;;;    (message "m3::pp-region-safe (3)") (sit-for 2)
    (if (buffer-file-name)
	(let* ((len (length (buffer-file-name)))
	       (tail (substring (buffer-file-name) (- len 3) len)))
	  (cond
	   ((or (string-equal tail ".m3") (string-equal tail ".mg"))
	    (setq m3pp-type m3::pp-modunit))
	   ((or (string-equal tail ".i3") (string-equal tail ".ig"))
	    (setq m3pp-type m3::pp-defunit))
	   (t
	    (error "m3pp: pretty-print only .m3, .mg, .i3, or .ig files"))))
      (save-excursion
	(goto-char (point-min))
	(m3::forward-to-code (point-max))
	(cond
	 ((looking-at "INTERFACE")
	  (setq m3pp-type m3::pp-defunit))
	 ((looking-at "MODULE")
	  (setq m3pp-type m3::pp-modunit))
	 ((looking-at "\\(GENERIC\\|UNSAFE\\)")
	  (forward-word 1)
	  (m3::forward-to-code (point-max))
	  (cond
	   ((looking-at "INTERFACE")
	    (setq m3pp-type m3::pp-defunit))
	   ((looking-at "MODULE")
	    (setq m3pp-type m3::pp-modunit))
	   (t
	    (error "m3pp: buffer is not an interface or module.")))))))

    (message "m3pp: working ...")
    (setq m3::pp-in-progress t)
    (cond
     ;; Empirically, this number seems to work; lengths over 8000 seem
     ;; to get hung up somewhere when using process-send-string.
     ((> (- end start) 4000)
      (let* ((num (mod (random) 1000))
	     (fn-in (concat "/tmp/" (getenv "USER") "-m3pp-in-"
			    (format "%d" num)))
	     (fn-out (concat "/tmp/" (getenv "USER") "-m3pp-out-"
			     (format "%d" num))))
;;;	(message "random-filename is %s" fn) (sit-for 1)
	(goto-char end) (insert "")
	(goto-char start) (insert "")
	(write-region start end fn-in nil 'no-msg)
	(goto-char start) (delete-char 1)
	(goto-char end) (delete-char 1)
	(let ((cur-buffer (current-buffer)))
	  (get-buffer-create "m3::pp-output")
	  (set-buffer "m3::pp-output")
	  (shell-command (concat "m3pp -ZZG < " fn-in " > " fn-out))
	  (insert-file fn-out)
	  (set-buffer cur-buffer))))
     (t
      (process-send-string 
       m3::pp-process
       (concat m3pp-type (buffer-substring start end) m3::pp-endunit "\n"))
      (while m3::pp-in-progress
	(accept-process-output m3::pp-process))))
;;;    (setq m3::pp-start (point-marker))
    (kill-region start end)
    (insert-buffer "m3::pp-output")
    (save-excursion
      (set-buffer "m3::pp-output")
      (if (re-search-backward "(\\* SYNTAX ERROR " (point-min) t)
	  (progn
	    (beep)
	    (message "m3pp: syntax error"))
	(progn ;else
	  (message "m3pp: done"))))
    (goto-char return-point)))

;;    (if (not (pos-visible-in-window-p))
;;	(let ((dotval (+ (point-marker))))
;;	  (line-to-bottom-of-window)
;;	  (goto-char dotval)))))

(defun m3::pp-filter (&process &str)
  (save-excursion
    (get-buffer-create "m3::pp-output")
    (set-buffer "m3::pp-output")
    (goto-char (point-max))
    (insert &str)
    (if (search-backward m3::pp-endunit (point-min) t) 
	(progn
	  (delete-char 2)
	  (setq m3::pp-in-progress nil)))))

(defun m3::pp-find-format-unit ()
;;;  (message "Beginning of format region") (sit-for 2)
  (set-mark (point))
  (m3::end-of-defun 1)
;;;  (message "End of format region") (sit-for 2)
  (exchange-point-and-mark)
  nil)

;;;----------- SRC-specific (but adaptable) stuff ----

(defvar m3::path-alist nil
  "Alist with entries of the form:
   <DIRECTORY, M3MAKEFILE-MOD-DATE, PATH-AS-DIR-LIST>
   If DIRECTORY has an entry on this list, its m3makefile has been processed
to yield the path PATH-AS-DIR-LIST at a time in the past when the modification
time of the m3makefile was M3MAKEFILE-MOD-DATE.  If the m3makefile has not
been modified since then, it is safe to use the cached path.")

(defvar m3::path-default nil
  "The search path corresponding to the 'be' directory.")

(defvar m3::path-default-time nil
  "The modification date of the default m3path file when it was last read.")

(defvar m3::derived-dir "DS"
  "Subdirectories into which emacs assumes m3build will put derived files.")

(defun m3::read-path ()
  "Assumes that the current directory is a (possibly non-proper) subdirectory
of the src directory of the current package, that that src directory
contains the m3makefile for the package, and that the package contains
one subdirectory named src, and it is an immediate subdirectory
of the package directory.  Constructs and returns the search path associated
with that m3makefile, if this m3makefile exists; otherwise returns NIL.  May
do caching based on the modification time of the m3makefile."
  ;; First, find the src directory.
  (let ((old-dd default-directory))
    (when (not (m3::find-main-src-dir))
      (setq default-directory old-dd)
      (error "Unable to find main src directory."))
    (let ((entry (assoc default-directory m3::path-alist)))
      (cond
       (entry
	(let ((imp-tab-name (concat "../" m3::derived-dir "/.M3IMPTAB")))
	  (cond
	   ((file-exists-p imp-tab-name)
	    (let ((mod-time (m3::get-mod-time imp-tab-name)))
	      ;; Do we have this cached?
	      (cond
	       ((let ((cached-date (cadr entry)))
		  (m3::time-le mod-time cached-date))
		;; we got a cache hit that is still valid.
		(setq default-directory old-dd)
		(nth 2 entry))
	       (t
		;; Cache entry was invalid.  Update it.
		(m3::update-m3-alist)
		(setq entry (assoc default-directory m3::path-alist))
		(setq default-directory old-dd)
		(nth 2 entry)))))
	   (t
	    (message "%s file is no longer-present.")))))
       (t nil)))))

(defun m3::find-main-src-dir ()
  "Moves the current directory to the main 'src' directory of the current
package, if it can find it.  Returns non-nil iff it finds one."
  (while 
      (and (not (string=
		 (file-name-nondirectory (substring default-directory 0 -1))
		 "src"))
	   (not (string= default-directory "/")))
    (cd ".."))
  (and (not (string= default-directory "/"))
       ;; We found the src directory.  Make sure.
       (if (not (string= (file-name-nondirectory
			  (substring default-directory 0 -1))
			 "src"))
	   (error "INTERNAL")
	 t)))

(defun m3::search-for-pkg (off)
  "Asserts that the current directory has special imports not covered by the
default, so we should use parse and use a directory-specific search-path
for it.  With a prefix-argument, removes search-path entry for current package.
"
  (interactive "P")
  (let ((old-dd default-directory))
    (when (not (m3::find-main-src-dir))
      (setq default-directory old-dd)
      (error "Unable to find main src directory."))
    (cond
     (off
      (delete-if '(lambda (elem) (string= (car elem) default-directory))
		 m3::path-alist))
     (t
      (when (not (assoc default-directory m3::path-alist))
	(setq m3::path-alist (cons (list default-directory '(0 0) nil)
				   m3::path-alist)))))))

(defun m3::update-m3-alist ()
  "m3::path-alist has an out-of-date entry for the current directory.
Make that entry valid again.  Requires that we're in the main 'src'
directory of the current package, and that the appropriate .M3IMPTAB
exists."
  (setq m3::path-alist
	(delete-if '(lambda (elem) (string= (car elem) default-directory))
		   m3::path-alist))
  ;; Find the .M3IMPTAB for the current directory, if it exists.
  (let ((imp-tab-name (concat "../" m3::derived-dir "/.M3IMPTAB")))
    (if (not (file-exists-p imp-tab-name)) (error "INTERNAL"))
    (message "Reading %s for search path..." imp-tab-name)
    (let ((sav-buffer (current-buffer))
	  (m3path-buffer (create-file-buffer "m3path"))
	  (path nil))
      (set-buffer m3path-buffer)
      (delete-region (point-min) (point-max))
      (shell-command-on-region
       (point-min) (point-max)
       (concat "grep '^@.*$' " imp-tab-name " | sed -e 's/^@//'")
       t)
      (goto-char (point-min))
      (while (< (point) (point-max))
	(let ((dir (buffer-substring 
		    (point) (progn (end-of-line nil) (point)))))
	  (if (> (length dir) 0)
	      (setq path (cons dir path)))
	  (forward-line 1)))
      (set-buffer sav-buffer)
      (setq m3::path-alist
	    (cons (list default-directory (m3::get-mod-time imp-tab-name) path)
		  m3::path-alist)))))

(defun m3::get-mod-time (fn)
  "Assumes fn exists; returns modification date as two-element-list."
  (let ((attrs (file-attributes fn))) (nth 5 attrs)))

(defun m3::time-le (t1 t2)
  "t1 and t2 are times represented as two-element lists of (16 bit) integers.
Returns non-NIL iff t1 <= t2."
  (or (< (car t1) (car t2))
      (and (= (car t1) (car t2))
	   (<= (cadr t1) (cadr t2)))))
    
(defconst m3::be-pkg "/proj/m3/pkg/be/")

(defun m3::read-default-path ()
  "Ensures that m3::path-default has an up-to-date value."
  (let ((fn (concat m3::be-pkg m3::derived-dir "/m3path")))
    (cond
     ((file-exists-p fn)
      (let ((tm (m3::get-mod-time fn)))
	(when (or (not m3::path-default-time)
		  (not (m3::time-le tm m3::path-default-time)))
	  (message "Reading default m3path...")
	  (save-excursion
	    (let ((sav-buffer (current-buffer))
		  (path nil))
	      (find-file-read-only fn)
	      (goto-char (point-min))
	      (while (< (point) (point-max))
		(let ((dir (buffer-substring 
			    (point) (progn (end-of-line nil) (point)))))
		(if (> (length dir) 0)
		    (setq path (cons dir path)))
		(forward-line 1)))
	      (let ((m3path-buffer (current-buffer)))
		(set-buffer sav-buffer)
		(kill-buffer m3path-buffer)
		(setq m3::path-default (cons "." path))
		(setq m3::path-default-time tm)))))))
     (t
      (message "Default m3path file '%s' does not exist..." fn)
      ))))

;;; stolen from lib-complete, 
;;; Author          : Mike Williams <mike-w@cs.aukuni.ac.nz>
;;; Created On      : Sat Apr 20 17:47:21 1991
;;; Last Modified By: Mike Williams
;;; Last Modified On: Tue Jun 18 12:53:08 1991

(defun m3::locate-file (FILE SEARCH-PATH &optional SUFFIX-LIST PRED)
  "Search for FILE on SEARCH-PATH (list).  If optional SUFFIX-LIST is
provided, allow file to be followed by one of the suffixes.
Optional second argument PRED restricts the number of files which
may match.  The default is file-exists-p."
  (if (not SUFFIX-LIST) (setq SUFFIX-LIST '("")))
  (if (not PRED) (setq PRED 'file-exists-p))
  (if (file-name-absolute-p FILE) (setq SEARCH-PATH '(nil)))
  (if (equal FILE "") (error "Empty filename"))
  (let ((filelist 
	 (mapcar 
	  (function (lambda (ext) (concat FILE ext)))
	  SUFFIX-LIST)))
    ;; Search SEARCH-PATH for a readable file in filelist
    (catch 'found
      (while SEARCH-PATH
	(let ((filelist filelist))
	  (while filelist
	    (let* ((expanded (expand-file-name (car filelist)
					       (car SEARCH-PATH)))
		   (filepath (substitute-in-file-name expanded)))
	      (if (funcall PRED filepath)
		  (throw 'found filepath)))
	    (setq filelist (cdr filelist))))
	(setq SEARCH-PATH (cdr SEARCH-PATH))))
    ))

(defvar m3::show-file-other-frame t
  "If non-nil and using emacs19, files found using
m3::show-interface or m3::show-implementation will be displayed on
new screens.") 

(defun m3::show-interface (&optional arg)
  "Find a Modula-3 interface. 
If ARG is a string, it is the name of the interface.  If ARG is nil,
get the name from the text around the point.  Otherwise, ARG should be 
an epoch mouse position and the name is found around that position.
If the current directory has an 'm3path' file, reads that to get a
search path; otherwise, uses m3::path.  Then find the file that
contains that interface.  Under gnuemacs, or if using epoch and
m3::show-interface-other-frame is nil, show the interface in another
window of the current screen.  If using epoch and
m3::show-interface-other-frame is non-nil, show the interface in a
new screen of the Modula-3 pool; the screens in that pool are in the
class m3::poolclass. The Modula-3 pool is of size m3::poolsize."
  (interactive)
  (let ((interface (if (stringp arg) arg (m3::ident-around-point))))
    (m3::show-file-work interface 'interface)))

(defun m3::show-spec (&optional arg)
  "Find a Modula-3 spec file."
  (interactive)
  (let ((interface (if (stringp arg) arg (m3::ident-around-point))))
    (m3::show-file-work interface 'specification)))

(defvar m3::trait-path
  '("." "/udir/horning/TheBook/handbook" "/proj/m3/pkg/lm3-traits/traits"
    "/udir/kjones/larch/LM3/pkg/TEST")
  "The list of directories to search for lsl files...")
  
(defun m3::show-trait (&optional arg)
  "Find an LSL trait file."
  (interactive)
  (let* ((trait (if (stringp arg) arg (m3::ident-around-point)))
	 (file (m3::locate-file (concat trait ".lsl") m3::trait-path)))
    (if file
	(m3::show-file file)
      (error "Unable to locate trait %s." trait))))

(defun m3::ident-around-point ()
  (save-excursion
    (let (end)
      (re-search-forward "[^A-Za-z0-9_]" nil t)
      (backward-char)
      (setq end (point))
      (re-search-backward "[^A-Za-z0-9_]" nil t)
      (forward-char)
      (buffer-substring (point) end))))


(defun m3::show-file-work (interface kind)
  (m3::read-default-path)
  (let ((path (m3::read-path)))
    (message "Searching for file...")
    (cond
     ((eq kind 'interface)
      (setq filename
	    (or (m3::locate-file interface path '(".i3" ".ig"))
		(m3::locate-file interface m3::path-default '(".i3" ".ig"))
		)))
     ((eq kind 'specification)
      (setq filename
	    (or (m3::locate-file (concat interface ".lm3")  path)
		(m3::locate-file (concat interface ".lm3")  m3::path-default)
		))))
    (if (not filename)
	(message "Unable to locate %s '%s'" kind interface)
      (message "found.")
      (m3::show-file filename))))


(defun m3::show-file (filename)
  (cond 
   ((and m3::show-file-other-frame (fboundp 'find-file-other-frame))
    (find-file-other-frame filename))
   (t
    (find-file-other-window filename))))

(defun m3::show-implementation ()
  "If the current buffer contains an interface file, attempts to find
the implementation of that interface in the same directory as the
interface, and displays that file if it is found.  If using epoch
and m3::show-file-other-frame is non-nil, displays the file in a new
screen."
  (interactive)
  (let* ((bfn (buffer-file-name))
	 (ext (m3::get-extension (file-name-nondirectory bfn))))
    (if (and bfn
	     (or (equal ext ".i3") (equal ext ".ig")))
	(progn
	  ;; First, find the true directory of the file.
	  (let* ((true-name (m3::file-true-name bfn))
		 (true-dir (file-name-directory true-name))
		 (interface-name (m3::strip-extension
				  (file-name-nondirectory bfn)))
		 (save-buffer (current-buffer))
		 (new-buffer (get-buffer-create "*implementation*"))
		 (impl-name (concat true-dir interface-name
				    (if (equal ext ".i3")
					".m3"
				      ".mg"))))
	    (if (not (file-exists-p impl-name))
		(if (not (equal ext ".i3"))
		    (setq impl-name nil)
		  (save-excursion
		    (setq impl-name nil)
		    (set-buffer new-buffer)
		    (delete-region (point-min) (point-max))
		    (let ((grep-cmd
			   (concat "cd " true-dir ";"
				   "egrep -l "
				   "'(MODULE +" interface-name ")|"
				   "(MODULE +[a-zA-Z_][a-zA-Z_0-9]* +EXPORTS +"
				   "([a-zA-Z_][a-zA-Z_0-9]*, *)*"
				   interface-name ")' *.m3")))
		      (message "Searching for exporter of %s..." interface-name
)
		      (shell-command-on-region (point-min) (point-min)
					       grep-cmd t)
		      (message "done."))
		    (goto-char (point-min))
		    (if (> (point-max) (point-min))
			(progn
			  (setq impl-name (buffer-substring
					   (point-min)
					   (save-excursion
					     (end-of-line nil) (point))))
			  (message "Implementation is %s." impl-name))))))
	    (if (not impl-name)
		(message "Implementation of %s not found in directory %s."
			 interface-name true-dir)
	      (m3::show-file (concat true-dir impl-name)))))
      (message "Current file does not appear to be an interface."))))

		       
(defun m3::file-true-name (fn)
  (let ((continue t))
    (while continue
      (let* ((fa (file-attributes fn))
	     (fa1 (car fa)))
	(cond
	 ((or (eq fa1 t) (not fa1))
	  (setq continue nil))
	 (t
	  ;; Otherwise, fa is a symbolic link; follow it.
	  (setq fn fa1)))))
    (expand-file-name fn)))
	  

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

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

-- 
======================================================================
Dave Detlefs
DEC Systems Research Center
Palo Alto, CA


======================================================================= 83 ===
Date:    22 Jan 1995 20:08:05 GMT
From:    bm@shadow.cs.columbia.edu (Blair MacIntyre)
Subject: Re: modula3.el - blink-matching-open problem in Emacs 19 ...

>>>>> On 20 Jan 1995 23:03:39 GMT, detlefs@src.dec.com (Dave Detlefs)
>>>>> said:

Dave> Blair MacIntyre writes:

Dave>     I was just wonder if anyone else had this problem and had a
Dave>     workaround.  When I close a comment in Emacs, I get the
Dave>     error

Dave>     Signalling: (wrong-type-argument number-or-marker-p nil)
Dave>       blink-matching-open()

Dave>     This doesn't seem to happen in Emacs-18, so I'm wondering if
Dave>     it's something weird with 19, and if anybody has a fix.
Dave>     Turning of blink-matching-paren obviously fixes it, but
Dave>     that's not entirely satisfactory.

Dave> I don't have this problem with emacs19.  Here is the version of
Dave> modula3.el we're currently using at SRC; perhaps yours is older...

Well, mine is the one included in the v3.4 distribution ... it looks
pretty similar.  Must be something else.
--
Blair MacIntyre (bm@cs.columbia.edu), Graduate Student (Graphics and UI Lab)

smail: Dept. of Computer Science, 450 Computer Science Building, 500 W 120 St.
       Columbia University, New York, NY 10027


======================================================================= 84 ===
Date:    22 Jan 1995 19:43:11 GMT
From:    schwartz@galapagos.cse.psu.edu (Scott Schwartz)
Subject: Re: Request for status on v. 3.4 (SPARC)

nayeri@gte.com (Farshad Nayeri) writes:
> Please don't take these numbers seriously,

Why not?  If M3 has such a huge runtime system, that's important to
know.  Is there some subtle aspect of the language that makes it so
difficult to implement efficienty?



======================================================================= 85 ===
Date:    23 Jan 95 01:02:39
From:    nayeri@gte.com (Farshad Nayeri)
Subject: Re: Request for status on v. 3.4 (SPARC)


In article <SCHWARTZ.95Jan22144311@galapagos.cse.psu.edu> schwartz@galapagos.cs
e.psu.edu (Scott Schwartz) writes:

   nayeri@gte.com (Farshad Nayeri) writes:
   > Please don't take these numbers seriously,

   Why not?  

I am sorry, I was not being clear. I will try again:

"Please don't take my numbers seriously as performance measurements go
since I haven't taken real care of making sure that they are
accurate."

   If M3 has such a huge runtime system, that's important to know. 

My judgement for the current size of the runtime system is "moderate".
For my case, the trade-offs have been well worth it. (Note that just
by stripping the binaries you may half their size!)

   Is there some subtle aspect of the language that makes it so
   difficult to implement efficienty?

Quite the oppossite: M3's design is a delicate balance of "high-level
programming" features that have been massaged so that they can be
implemented efficiently. In fact, there are some subtle aspects of the
language that makes it easier to implement efficiently.

Note that "to implement efficiently" can mean different things in
different contexts. Do you mean run-time, development, compile-time,
or space efficiency? 

-- Farshad
--
Farshad Nayeri
nayeri@gte.com


======================================================================= 86 ===
Date:    24 Jan 1995 06:00:40 GMT
From:    schwartz@galapagos.cse.psu.edu (Scott Schwartz)
Subject: Re: Request for status on v. 3.4 (SPARC)

nayeri@gte.com (Farshad Nayeri) writes:
| Note that "to implement efficiently" can mean different things in
| different contexts. Do you mean run-time, development, compile-time,
| or space efficiency? 

I mean, why is the runtime system so huge?  If it takes 400K just to
get off the ground, something is wrong.  

My idea of a well written program is the shell I normally use (author
Byron Rakitzis).  On a sparc running sunos4.1, the statically linked
version is this big:

; size /bin/rc
text	data	bss	dec	hex
73728	16384	6944	97056	17b20

This shell uses dynamic memory allocation, an lalr parser, a string
formatting library, and various nontrivial data structures.  The
source is about 7000 lines of C.  If it was written in m3 instead of
C, the runtime system would be an order of magnitude larger than the
program itself.  That's hard to ignore.

Please understand, I don't mean to pick on m3; plenty of things are
bloated these days, after all.  I'm bitching because I like m3.


======================================================================= 87 ===
Date:    Tue, 24 Jan 1995 09:45:00 -0500
From:    gwyant@cloyd.East.Sun.COM (Geoffrey Wyant - Sun Microsystems Labs BOS)
Subject: Re: Request for status on v. 3.4 (SPARC)

	<NAYERI.95Jan20171052@bermuda.gte.com>
	<SCHWARTZ.95Jan22144311@galapagos.cse.psu.edu>
	<NAYERI.95Jan23010239@tahoe.gte.com>
	<SCHWARTZ.95Jan24010040@galapagos.cse.psu.edu>In-Reply-To: <SCHWARTZ.95
Jan24010040@galapagos.cse.psu.edu>
Distribution: world
X-Received: from suneast.East.Sun.COM by East.Sun.COM (4.1/SMI-4.1)
X-Received: by src-mail.pa.dec.com; id AA24308; Tue, 24 Jan 95 06:53:13 -0800
X-Newsgroups: comp.lang.modula3
X-Content-Length: 3002
X-Received: from cloyd.East.Sun.COM by suneast.East.Sun.COM (5.0/SMI-4.1-900117
)
X-Received: from Sun.COM by inet-gw-1.pa.dec.com (5.65/10Aug94)
X-Received: by cloyd.East.Sun.COM (5.x/SMI-SVR4)
X-Received: from East.Sun.COM (east.East.Sun.COM) by Sun.COM (sun-barr.Sun.COM)
X-Received: by src-news.pa.dec.com; id AA21803; Tue, 24 Jan 95 06:53:18 -0800

Scott Schwartz writes:
 > nayeri@gte.com (Farshad Nayeri) writes:
 > | Note that "to implement efficiently" can mean different things in
 > | different contexts. Do you mean run-time, development, compile-time,
 > | or space efficiency? 
 > 
 > I mean, why is the runtime system so huge?  If it takes 400K just to
 > get off the ground, something is wrong.  
 > 
 > My idea of a well written program is the shell I normally use (author
 > Byron Rakitzis).  On a sparc running sunos4.1, the statically linked
 > version is this big:
 > 
 > ; size /bin/rc
 > text	data	bss	dec	hex
 > 73728	16384	6944	97056	17b20
 > 
 > This shell uses dynamic memory allocation, an lalr parser, a string
 > formatting library, and various nontrivial data structures.  The
 > source is about 7000 lines of C.  If it was written in m3 instead of
 > C, the runtime system would be an order of magnitude larger than the
 > program itself.  That's hard to ignore.
 > 
 > Please understand, I don't mean to pick on m3; plenty of things are
 > bloated these days, after all.  I'm bitching because I like m3.

The runtime proper provides quite a bit more functionality than the C runtime
gives you. In particular, it gives you:

  - Threads
  - Exception Handling
  - Text Manipulation
  - Incremental, conservative, generational GC
  - weak references
  - fingerprints 
  - unix interfaces 
  - runtime type information

on Solaris 2.4, the shared library for the M3 runtime (m3core) 
is about 400K stripped (448084 to be exact). For comparison, libc 
on the same release is 476983 bytes.  On SunOS 4.1.3, a stripped libc shared 
library is also 400K. Given that these two libraries have essentially the same 
role in life and libm3 gives you much more functionality, I'm not sure there is
 
all that much to complain about. It would be possible to build a 
version of 'libm3' that didn't require 'libc' to be linked at all, and I would
expect that a commercial implementation might do just that. 

Carefully written C programs may be smaller than the equivalent M3 programs 
due to the fact that object modules in 'libc' tend to be pretty much isolated
from each other, whereas 'libm3core' tends to have a fair number of references
between the components. Thus in any given application, all of 'libm3core' will 
be
pulled in, whereas only a subset of 'libc' will be pulled into the application.
 As a research project, SRC has not chosen to focus on building minimal-sized i
mages, 
but has tended to focus on higher-level functionality.

I'm not sure that it  is entirely fair to compare Modula-3 with C. They have di
fferent
goals and this has led to differences in the functionality provided. Also Modul
a-3
programmers program in a different style than C programmers writing shells. I t
hink a 
more accurate (or interesting) comparison would be between Modula-3 and Smallta
lk or
Modula-3 and Eiffel. 
  
--geoff

Geoff Wyant
Geoff.Wyant@east.sun.com
Sun Microsystems Laboratories, Inc.

2 Elizabeth Drive
Chelmsford, Ma.
01824


======================================================================= 88 ===
Date:    Tue, 24 Jan 1995 15:06:16 GMT
From:    freeman@coolidge.coolidge.grenoble.xerox.fr (Steve Freeman)
Subject: European Users' group meeting at ECOOP?


Is anyone interested in organising/speaking at/attending an M3
Users Group at ECOOP (in Aarhus) this year?

Could you drop me a note (or post here) and maybe we can get something
started?

steve
-- 
- - - - - - - - - - - - - - - - - - - - - - - - - -
Dr. Steve Freeman, Research Scientist, Rank Xerox France.

Surface:  Rank Xerox Research Centre,
          6, chemin de Maupertuis, 38240 Meylan, France.
Internet: steve.freeman@xerox.fr
Phone:    +33 76 61 50 21
Fax:      +33 76 61 50 99


but wotthehel wotthehel
toujours gai
  -- mehitabel the cat


======================================================================= 89 ===
Date:    24 Jan 1995 20:04:22 GMT
From:    schwartz@galapagos.cse.psu.edu (Scott Schwartz)
Subject: Re: Request for status on v. 3.4 (SPARC)

gwyant@cloyd.East.Sun.COM (Geoffrey Wyant - Sun Microsystems Labs BOS) writes:
| The runtime proper provides quite a bit more functionality than the C runtime
| gives you. 

Does it really take 400K to get those features?  Features are useless
if they are too expensive.  Oberon provides that kind of stuff in a
very much smaller package.

| As a research project, SRC has not chosen to focus on building
| minimal-sized images, but has tended to focus on higher-level
| functionality.

As I've said, I think m3 is very nice, and I applaud the good people
at SRC.  At the same time, I don't think it is fair to dismiss the
issue.  Computers are finite and efficiency counts.

| I think a more accurate (or interesting) comparison would be between
| Modula-3 and Smalltalk or Modula-3 and Eiffel.

As to that, I've used Smalltalk on PCs that were far too small to run
SRC m3.


======================================================================= 90 ===
Date:    Wed, 25 Jan 1995 10:23:22 -0500
From:    gwyant@cloyd.East.Sun.COM (Geoffrey Wyant - Sun Microsystems Labs BOS)
Subject: Re: Request for status on v. 3.4 (SPARC)

	<9501241445.AA22145@cloyd.East.Sun.COM>
	<SCHWARTZ.95Jan24150422@galapagos.cse.psu.edu>Cc: nayeri@gte.com
In-Reply-To: <SCHWARTZ.95Jan24150422@galapagos.cse.psu.edu>
Distribution: world
X-Received: from suneast.East.Sun.COM by East.Sun.COM (4.1/SMI-4.1)
X-Received: by src-mail.pa.dec.com; id AA25075; Wed, 25 Jan 95 10:29:04 -0800
X-Newsgroups: comp.lang.modula3
X-Content-Length: 3837
X-Received: from cloyd.East.Sun.COM by suneast.East.Sun.COM (5.0/SMI-4.1-900117
)
X-Received: from Sun.COM by inet-gw-2.pa.dec.com (5.65/10Aug94)
X-Received: by cloyd.East.Sun.COM (5.x/SMI-SVR4)
X-Received: from East.Sun.COM (east.East.Sun.COM) by Sun.COM (sun-barr.Sun.COM)
X-Received: by src-news.pa.dec.com; id AA18387; Wed, 25 Jan 95 10:29:26 -0800

Scott Schwartz writes:
 > gwyant@cloyd.East.Sun.COM (Geoffrey Wyant - Sun Microsystems Labs BOS) write
s:
 > | The runtime proper provides quite a bit more functionality than the C runt
ime
 > | gives you. 
 > 
 > Does it really take 400K to get those features?  Features are useless
 > if they are too expensive.  Oberon provides that kind of stuff in a
 > very much smaller package.

Well, Oberon makes a number of simplifying assumptions. First, threads are
non-preemptive. This elimates the locking and scheduling issues entirely. Secon
dly, 
the garbage collector is a simple mark&sweep GC which is easy to implement but 
doesn't scale particularly well. The garbage collector in M3 is fairly sophisti
cated.
The support for preemptive threads in M3 complicates the garbage collector some
what,
thus adding to the size of the runtime. Additionally, Oberon doesn't have excep
tions. 
This makes the runtime and libraries smaller.One reason they are smaller is tha
t the 
SRC implementation uses PC tables so that exception handlers can be quickly loc
ated. Which 
of these simplifying assumptions would you make for M3 and why ?

Finally, and here I think is a key difference. Oberon (and I'm talking about th
e
ETH Zurich implementation) is a programming language, programming environment, 
and
operating system rolled into one. This gives considerable leverage that the SRC
 M3
implementation doesn't have. In particular, they get to define their own object
file format and own loader. Some of the size of the SRC object files come from 
having
to encode M3 functionality into standard object file formats and from having to
duplicate some of the information which is in the object file (procedure & type
 names,
type information, etc.)  Portability comes at a price. Would you have SRC conce
ntrate
on an optimized MIPS-specific implementation and not worry about portability an
d the
ability to use standard tools ?

I know the counter-argument that you will make here, which is that Oberon has b
een
ported to a number of platforms and still manages to have small platform-specif
ic 
implementations. The difference lies in the size of the development groups. Wir
th 
essentially has an endless supply of graduate students that can put in arbitrar
y amounts
of time to bring up a platform-specific Oberon implementation. DEC SRC doesn't 
really
have a large full-time M3 group. The M3 group is, I think, about two people. Ot
her SRC
researchers contribute to the runtime as needed, but there is no one that works
 on
the runtime full-time and who's sole job is ehancing and porting the runtime. A
lso 
bear in mind that SRC has essentially only MIPS and Alpha machines. All of the 
other
ports come from outside. Given this, I would say that SRC has done more than a 
reasonable
job on the M3 implementation.

 > 
 > | As a research project, SRC has not chosen to focus on building
 > | minimal-sized images, but has tended to focus on higher-level
 > | functionality.
 > 
 > As I've said, I think m3 is very nice, and I applaud the good people
 > at SRC.  At the same time, I don't think it is fair to dismiss the
 > issue.  Computers are finite and efficiency counts.
 > 
 
I'm not dismissing the issue entirely. I personally believe that SRC has made t
he
right choices on what they choose to spend their research efforts on. I think t
hat
a commercial implementation of M3 could be made smaller by having more intimate
knowledge of object file formats. I personally don't feel that this is somethin
g
that SRC should be devoting resources to. If you really do like the language, a
nd
believe that the same functionality could be provided in considerably less spac
e,
I'll challange you  to take the SRC implementation and make it smaller. You hav
e all
of the sources available. If you succeed, then you will have provided a service
 to
everyone.

--geoff


======================================================================= 91 ===
Date:    25 Jan 95 11:36:24
From:    dagenais@gutrune.vlsi.polymtl.ca (Michel Dagenais)
Subject: Re: Request for status on v. 3.4 (SPARC)


   Does it really take 400K to get those features?  Features are useless
   if they are too expensive.  Oberon provides that kind of stuff in a
   very much smaller package.

Last time i checked the GC and threads in Oberon were "rudimentary".
Each background module is given a turn to do "a bit of work"
one after the other (i.e. non preemptive multi threading). The
garbage collection takes place between the turns, while the
stack is empty. Less functionality and less memory, there is
obviously a trade off. Pick the trade off which best matches to your needs.
--

Prof. Michel Dagenais        http://www.vlsi.polymtl.ca/dagenais/home/home.html
Dept of EE and Computer Eng.        dagenais@vlsi.polymtl.ca
Ecole Polytechnique de Montreal     tel: (514) 340-4029



======================================================================= 92 ===
Date:    Wed, 25 Jan 1995 17:10:07 GMT
From:    ljp@my21.sm.luth.se (Johan Persson)
Subject: [Q] Problem with VBT.MMToPixels()

Does anyone have any idea why my library version of
VBT.MMToPixels() insists on that 1mm <-> 1 pixels,
which on my screen certainly is not true, (it should be 4).

Should I put the blame on the X-server?

I'm currently using version 3.4 of m3, but I had the same
problem with 3.3.

The other routines that uses mm, e.g RigidVBT, behaves
as expected.

/Johan

---
Johan Persson, (ljp@sm.luth.se)
-- 
---         
Johan Persson                          http://www.sm.luth.se/~ljp/
Dept. of Computer Science
University of Lulea


======================================================================= 93 ===
Date:    25 Jan 1995 10:50:45 -0800
From:    bertrand@vienna.eiffel.com (Bertrand Meyer)
Subject: L'OBJET: A new journal (in French) on object technology.


[This message describes the launching of a new journal, in French,
entirely devoted to object technology.]

	Une nouvelle publication en langue francaise, la premiere a notre
connaissance a etre entierement consacree aux technologies objet, vient
d'etre creee:

		L'OBJET
		Logiciel, Reseaux, Bases de Donnees

	Le premier numero sera disponible debut mars pour la conference
TOOLS (Versailles, 6-10 mars).

	La revue est trimestrielle et parait les 1er mars, 1er juin, 1er
septembre et 1er decembre. Elle est consacree a tous les aspects des
technologies objets, couvre tous les domaines d'application (langages,
methodes, telecommunications, bases de donnees, finance, materiel,
intelligence artificielle etc.), et est ouverte a toutes les tendances
du domaine.

	La revue contiendra des articles d'information technique ainsi que
des nouvelles d'interet general et des offres d'emploi. Elle se veut un
trait d'union entre tous les membres de la communaute "Objet".
A ce titre n'hesitez pas a nous envoyer toute annonce susceptible
d'interesser les lecteurs: publications, conferences, realisations
industrielles, theses, formations universitaires, seminaires ...

	Redacteur en chef: Jean-Alain Hernandez (ENST Paris)
	Directeur de la Publication: Jean-Marc Nerson (SOL, Paris)
	Conseiller scientifique: Bertrand Meyer (ISE, Santa Barbara)
	Patronage: AFCET (a confirmer)
	Comite de Redaction (* = non confirme):

			Jean Bezivin (Univ. de Nantes)
			Pere Botella (Univ. Polyt. de Catalogne)
			Fiorella De Cindio (Universita di Milano)
			Pierre Desjardins (CITI, Laval - Quebec)
			Jean-Marc Eber* (Societe generale)
			Andre Flory (INSA)
			Nasser Kettani (CR2A)
			Sophie Gamerman (O2 Technology)
			Hafedh Mili (Univ. du Quebec a Montreal)
			Oscar Nierstrasz (Univ. de Berne)
			Jean Francois Perrot* (Laforia)
			Arnold Rochfeld (Consultant)
			Philippe Stephan (CALFP/Credit Agricole)
			Jean Bernard Stefani* (CNET)
			Patrick Valduriez (Inria)
			Jean Vaucher* (Univ. de Montreal)


	Abonnement annuel: 95 F (France), 120 F (autres pays europeens),
150 F (autres pays).

	Abonnements, offres d'emploi, publicite:
			SOL
			104 rue Castagnary
			75015 Paris
			Telephone 45 32 58 80, Telecopie 45 32 58 81,
			Courrier electronique <lobjet@eiffel.fr>

	Pour soumettre des articles ou envoyer des informations a publier :
			Jean-Alain Hernandez
				ENST, 46 rue Barrault 75634 Paris Cedex 13
			Courrier electronique <hernandez@enst.enst.fr>
-- 
Bertrand Meyer - ISE, Santa Barbara, California
805-685-1006, fax 805-685-6869, <bertrand@eiffel.com>
Web home page: http://www.eiffel.com
ftp://eiffel.com


======================================================================= 94 ===
Date:    Wed, 25 Jan 1995 18:23:46 PST
From:    janssen@parc.xerox.com (Bill Janssen)
Subject: Re: Request for status on v. 3.4 (SPARC)

	<9501241445.AA22145@cloyd.East.Sun.COM>Sender: janssen@parc.xerox.com (
Bill Janssen)
In-Reply-To: <9501241445.AA22145@cloyd.East.Sun.COM>
Distribution: world
X-Received: by holmes.parc.xerox.com id <16136>; Wed, 25 Jan 1995 18:23:49 -080
0
X-Received: by src-mail.pa.dec.com; id AA03895; Wed, 25 Jan 95 18:30:32 -0800
X-Received: from Messages.7.15.N.CUILIB.3.45.SNAP.NOT.LINKED.holmes.parc.xerox.
com.sun4.41
X-Received: from alpha.Xerox.COM by inet-gw-2.pa.dec.com (5.65/10Aug94)
X-Received: from holmes.parc.xerox.com ([13.1.100.162]) by alpha.xerox.com with
 SMTP id <14593(7)>; Wed, 25 Jan 1995 18:23:55 PST
X-Received: by src-news.pa.dec.com; id AA01207; Wed, 25 Jan 95 18:30:34 -0800
X-Illegal-Object: Syntax error in To: address found on alpha.xerox.com:

An interesting note:  I was told today that PARC Posix Portable Common
Runtime, a library that provides threads, garbage-collection, and
dynamic (or incremental) loading as library routines, is about 400k
stripped.

Bill


======================================================================= 95 ===
Date:    25 Jan 1995 23:56:00 GMT
From:    semb100@cus.cam.ac.uk (Simon Barber)
Subject: Static binding in Objects, Inlining and Defining operators

I am fairly new to M3, so please excuse me if the answers to any of these
questions are obvious.

1) I have recently been writing a program to manipulate MPEG streams in
Modula 3 and have come up with these problems. My initial structure for
the program had a separate module which defined a file object that was
buffered, and which I could perform bit aligned bit IO. This proved very
slow, I suspect due to the dynamic binding of my BitIO.T object. Reading
megabyte sized files several bits at a time is just too slow. I re-wrote
the program using inline procedures on a mpeg stream type, and now it runs
at an acceptable speed. Is there a way to define a static bound, and so
inlinable object method in Modula 3? I believe this can be done in C++,
and see this as a serious flaw in Modula 3 as a conender against C++ on
efficiency grounds.

2) In Modula 3 if I put <*INLINE*> before a procedure  signature in its
interface and before its definition in its module will it be inlined when
it's used in another module? (Under M3 v3.3 for Solaris?)

3) Sometimes it is very clumsey to express operations as
FunctionCall(Operand1, Operand2 etc etc), would it be an idea to include a
declarator OPERATOR to allow one to define operations. This would allow
overloading of operators and choose the appropriate function call
according to the types taken by the operator. The syntax could look
something like\

OPERATOR
  argument1 + argument2 = SpecialAdd(argument1, argument2);

The types would be culled from the procedure signature.
Does this go too far against the Modula 3 way of thinking? One way it
could be used - and easily abused - would be to alias function calls, but
call the currect function for the appropriately typed arguments - eg.

OPERATOR
  add(argument1, argument2) = SpecialAdd(argument1, argument2);

Comments and ideas?

Simon


======================================================================= 96 ===
Date:    26 Jan 1995 01:02:59 -0500
From:    kraizman@news.cs.columbia.edu (Michael Kraizman)
Subject: Status of various ports?

Sorry to sound like a broken record, but does anyone know the status
of the modula3 ports to NT and OS/2 and where to get them?

Thanks.


Michael Kraizman

----------------------------------------------------------------------
kraizman@cs.columbia.edu
-- 
Michael Kraizman


======================================================================= 97 ===
Date:    26 Jan 1995 20:56:53 GMT
From:    ckingsto%hookup.net@mail.hookup.net
Subject: Re: Modula-3 for OS/2

In <DAGENAIS.95Jan17083244@notung.vlsi.polymtl.ca>, dagenais@notung.vlsi.polymt
l.ca (Michel Dagenais) writes:
>
>From the FAQ. The last persons known to be working on such a port were
>Hendrik Boom hendrick@CAM.ORG and Craig Andrew Kingston 
>ckingsto@undergrad.math.uwaterloo.ca.
>--
>
>Prof. Michel Dagenais			    dagenais@vlsi.polymtl.ca
>Dept of Electrical and Computer Eng.
>Ecole Polytechnique de Montreal		    tel: (514) 340-4029

Hi Everyone - Craig here.

I am still continuing to work on the port - just got delayed for a couple of mo
nths
because of issues not relating to the port.  Not sure at this time of any dates
.

CRAIG
note: (my email has changed - not longer ckingsto@undergrad.math.uwaterloo.ca 
but is now ckingsto@hookup.net)


======================================================================= 98 ===
Date:    Thu, 26 Jan 95 18:58:05 -0500
From:    Dj Harris <dharri16@delphi.com>
Subject: Modula-3 for NT

Is there a port of M3 for NT ?
And where can I get it, if it exists ?
 
Thanks, Dj.


======================================================================= 99 ===
Date:    Fri, 27 Jan 1995 00:32:03 GMT
From:    eric@telebit.com (Eric Smith)
Subject: Anyone using Modula-3 for embedded systems?

I'd like to use Modula-3 for an embedded system (i.e., on bare metal rather
than in a Unix process), so I'd like to know if anyone has any experience
doing so.  Are there any published reports or papers on Modula-3 based
embedded systems?

I expect that I'll have to rewrite portions of the run time system, and add
support to the Thread interface for the specification of thread priority and
stack size.  Has anyone already done this sort of thing, or at least come up
with proposed extensions to Thread?

Thanks!
Eric


======================================================================= 100 ===
Date:    27 Jan 1995 01:22:29 GMT
From:    mbk@inls1.ucsd.edu (Matt Kennel)
Subject: Re: Request for status on v. 3.4 (SPARC)

Geoffrey Wyant - Sun Microsystems Labs BOS (gwyant@cloyd.East.Sun.COM) wrote:

: The runtime proper provides quite a bit more functionality than the C runtime
: gives you. In particular, it gives you:

:   - Threads
:   - Exception Handling
:   - Text Manipulation
:   - Incremental, conservative, generational GC
:   - weak references
:   - fingerprints 
:   - unix interfaces 
:   - runtime type information

: on Solaris 2.4, the shared library for the M3 runtime (m3core) 
: is about 400K stripped (448084 to be exact). For comparison, libc 
: on the same release is 476983 bytes.  On SunOS 4.1.3, a stripped libc shared 
: library is also 400K. Given that these two libraries have essentially the sam
e 
: role in life and libm3 gives you much more functionality, I'm not sure there 
is 
: all that much to complain about.

: Carefully written C programs may be smaller than the equivalent M3 programs 
: due to the fact that object modules in 'libc' tend to be pretty much isolated
: from each other, whereas 'libm3core' tends to have a fair number of reference
s
: between the components. Thus in any given application, all of 'libm3core' wil
l be
: pulled in, whereas only a subset of 'libc' will be pulled into the applicatio
n.
:  As a research project, SRC has not chosen to focus on building minimal-sized
 images, 
: but has tended to focus on higher-level functionality.

: I'm not sure that it  is entirely fair to compare Modula-3 with C. They have 
different
: goals and this has led to differences in the functionality provided. Also Mod
ula-3
: programmers program in a different style than C programmers writing shells. I
 think a 
: more accurate (or interesting) comparison would be between Modula-3 and Small
talk or
: Modula-3 and Eiffel. 

The Sather test suite, which exercises a fair number of library classes
and functions, compiles to 204K stripped on Solaris.  (Only needs dynamic
linking to libc).  Sather is a full-fledged OO language.

The Sather compiler itself compiles to 745K stripped.

There are a couple of reasons why it can make relatively small code:

	1)  It only makes code for those individual *routines* that
	    are reachable in the call graph from 'main'.  So if there
	    are some bloat routines in a big library that call some other
	    libraries, if you never call those routines in the first place,
	    they will not need to be brought in, and neither will the
	    things that they call either.

	2)  It distinguishes dispatched references from non-dispatched
	    references.  In realistic programs one often does not end up
	    needing dispatches in many places: the exact type of the
	    object is known.

	    Thus in combination with #1, when you know the exact type the
	    compiler need only generate code for specific routines, and not
	    all routines that might match a signature in any subtypes.
-----
I do not know how either of these points apply to Modula-3.

Please: This is not flame bait.  The goals are different: sather
does place a reasonably high premium on performance and efficiency.

Some space efficiency can probably still be wrung out of the Sather compiler,
as inlining isn't working yet.

The run-time is smaller, it does not include threads, but it does
have RTTI, GC and exceptions.

cheers
Matt


:   
: --geoff

: Geoff Wyant
: Geoff.Wyant@east.sun.com
: Sun Microsystems Laboratories, Inc.

: 2 Elizabeth Drive
: Chelmsford, Ma.
: 01824

--
-Matt Kennel  		mbk@inls1.ucsd.edu
-Institute for Nonlinear Science, University of California, San Diego
-*** AD: Archive for nonlinear dynamics papers & programs: FTP to
-***     lyapunov.ucsd.edu, username "anonymous".


======================================================================= 101 ===
Date:    Fri, 27 Jan 95 14:23:34 -0800
From:    rustan@pa.dec.com
Subject: Re: Anyone using Modula-3 for embedded systems?


A couple of years ago, I wrote a new runtime system for Modula-3.
The runtime system targeted a multicomputer called the Mosaic, built
by Chuck Seitz et al. at Caltech.  Each Mosaic processor only has 
64 KB RAM.  The implementation, described in

    Multicomputer Programming with Modula-3D
    Caltech Technical report Caltech-CS-TR-93-15, available on the 
    Web and through FTP (ftp://ftp.cs.caltech.edu/tr/cs-tr-93-15.ps.Z),

includes everything required by the language (except floating point 
support).  This includes threads, exceptions, and garbage collection.
The "D" (for "distributed") extension of Modula-3 adds remote procedure 
calls through method invocations of NETWORK objects (a new type in 
Modula-3D).  The Thread interface, like that provided in the SRC 
implementation, features a special Thread.Closure type called SizedClosure
that allows the stack size to be set, but Thread priorities are not
included.

  Rustan Leino


======================================================================= 102 ===
Date:    27 Jan 1995 15:09:38 GMT
From:    Jeffrey Fries P865 <pegasus1@bnr.ca>
Subject: Re: L'OBJET: A new journal (in French) on object technology.

bertrand@vienna.eiffel.com (Bertrand Meyer) wrote:
>
> 
> [This message describes the launching of a new journal, in French,
> entirely devoted to object technology.]
> 
> 	Une nouvelle publication en langue francaise, la premiere a notre
> connaissance a etre entierement consacree aux technologies objet, vient
> d'etre creee:
> 
> 		L'OBJET
> 		Logiciel, Reseaux, Bases de Donnees
> 
> 	Le premier numero sera disponible debut mars pour la conference
> TOOLS (Versailles, 6-10 mars).
> 
> 	La revue est trimestrielle et parait les 1er mars, 1er juin, 1er
> septembre et 1er decembre. Elle est consacree a tous les aspects des
> technologies objets, couvre tous les domaines d'application (langages,
> methodes, telecommunications, bases de donnees, finance, materiel,
> intelligence artificielle etc.), et est ouverte a toutes les tendances
> du domaine.
> 
> 	La revue contiendra des articles d'information technique ainsi que
> des nouvelles d'interet general et des offres d'emploi. Elle se veut un
> trait d'union entre tous les membres de la communaute "Objet".
> A ce titre n'hesitez pas a nous envoyer toute annonce susceptible
> d'interesser les lecteurs: publications, conferences, realisations
> industrielles, theses, formations universitaires, seminaires ...
> 
> 	Redacteur en chef: Jean-Alain Hernandez (ENST Paris)
> 	Directeur de la Publication: Jean-Marc Nerson (SOL, Paris)
> 	Conseiller scientifique: Bertrand Meyer (ISE, Santa Barbara)
> 	Patronage: AFCET (a confirmer)
> 	Comite de Redaction (* = non confirme):
> 
> 			Jean Bezivin (Univ. de Nantes)
> 			Pere Botella (Univ. Polyt. de Catalogne)
> 			Fiorella De Cindio (Universita di Milano)
> 			Pierre Desjardins (CITI, Laval - Quebec)
> 			Jean-Marc Eber* (Societe generale)
> 			Andre Flory (INSA)
> 			Nasser Kettani (CR2A)
> 			Sophie Gamerman (O2 Technology)
> 			Hafedh Mili (Univ. du Quebec a Montreal)
> 			Oscar Nierstrasz (Univ. de Berne)
> 			Jean Francois Perrot* (Laforia)
> 			Arnold Rochfeld (Consultant)
> 			Philippe Stephan (CALFP/Credit Agricole)
> 			Jean Bernard Stefani* (CNET)
> 			Patrick Valduriez (Inria)
> 			Jean Vaucher* (Univ. de Montreal)
> 
> 
> 	Abonnement annuel: 95 F (France), 120 F (autres pays europeens),
> 150 F (autres pays).
> 
> 	Abonnements, offres d'emploi, publicite:
> 			SOL
> 			104 rue Castagnary
> 			75015 Paris
> 			Telephone 45 32 58 80, Telecopie 45 32 58 81,
> 			Courrier electronique <lobjet@eiffel.fr>
> 
> 	Pour soumettre des articles ou envoyer des informations a publier :
> 			Jean-Alain Hernandez
> 				ENST, 46 rue Barrault 75634 Paris Cedex 13
> 			Courrier electronique <hernandez@enst.enst.fr>
> -- 
> Bertrand Meyer - ISE, Santa Barbara, California
> 805-685-1006, fax 805-685-6869, <bertrand@eiffel.com>
> Web home page: http://www.eiffel.com
> ftp://eiffel.com


What did ya say ?

huh ?



======================================================================= 103 ===
Date:    27 Jan 95 07:44:56
From:    nayeri@gte.com (Farshad Nayeri)
Subject: Re: Modula-3 for NT

In article <xe44q+9.dharri16@delphi.com> Dj Harris <dharri16@delphi.com> writes
:

   Is there a port of M3 for NT ?
   And where can I get it, if it exists ?

   Thanks, Dj.

Dj, 

Yes, there is. SRC Modula-3 has been ported to NT (it actually
compiles to native code!)

You can find it in gatekeeper.dec.com:/pub/DEC/Modula-3/release-3.4

There are also various DOS ports which should run in emulation, but
you are probably better off using the NT port. See the FAQ for more
info.

-- Farshad

--
Farshad Nayeri
nayeri@gte.com


======================================================================= 104 ===
Date:    25 Jan 1995 18:02:46 -0800
From:    rro@Tera.COM (Rod Oldehoeft)
Subject: Re: Request for status on v. 3.4 (SPARC)

On the discussion about the size of M3 executables:  this is often
a problem with "young" language software--the same was true, in 
spades, for Ada.

That said, one wonders just what library routines are present in
a "Hello World" M3 executable.  One should look before going too much
further in this discussion.   I cannot easily check myself just now,
since I'm in a temporary place at the moment.

If there really is thread software in there, for example, it would be
disappointing. The idea of minimizing the strength of connection among
functions is not a new idea, just a good one.  Back to the young
software point, this is just not on the top of the list for
implementors.  A commercial motivation would clearly help.

Just my $.02.



======================================================================= 105 ===
Date:    27 Jan 1995 15:34:10 GMT
From:    root@owl.bias.Uni-Bremen.DE (Jochen Skupin)
Subject: Problems with M3 V3.4 and Solaris 2.3

Hello, 

I'm trying to install the new Modula3 version 3.4 on my Sparcstation5
under Solaris 2.3 with gcc 2.6.3. The bootstrap installation succeded 
after replacing the boot-SOLgnu/m3cc/gcc/va-sparc.h file by it's newer
version from gcc 2.6.3 (as mentioned in this list a few days before).

Installing the m3-packages still makes problems. Not all packages compile
without errors (Which doesn't bother me to much, because I don't need them 
all).

In m3core/src/runtime/SOLgnu/RTThreadC.c I have replaced 
	#include <setjmp.h>
with
	#include </usr/include/setjmp.h>
to get it compiled.

At this stage compiling and running of the "hello world" programm works.
But the compiled packages (Tetris, Cube ...) won't run. They all stop with
the error (And that what's bothering me.):

	***
	*** runtime error:
	***    Exception "Date.Error" not in RAISES list
	***

	Abort - core dumped

I have no clue, what's happening here (I'm wether used to work with Modula3
nor UNIX nor C :-( ). Does anybody know how to solve this problem?

Thanks in advance
	Jochen Skupin

PS: I noticed that libs (for example libm3core.so) don't get installed (shipped
?)
in the /usr/local/lib/m3/SOLgnu folder as they should. Instead they are in
/usr/local/lib/m3/pkg/package-name/SOLgnu. 
The templates/SOLgnu-file reads as:

	readonly TARGET = "SOLgnu"
	readonly DEFAULT_BUILD_DIR = TARGET

	INSTALL_ROOT = "/usr/local/"
	%-- handy for installations that keep all M3 stuff together

	BIN_INSTALL   = INSTALL_ROOT & "bin"                % executables
	LIB_INSTALL   = INSTALL_ROOT & "lib/m3/" & TARGET   % libraries
	                                ^^^^^^^^^^^^^^^^^ this should do the tr
ick I think,
	                                                  but it doesn't :-(
	DOC_INSTALL   = INSTALL_ROOT & "lib/m3/doc"         % documents
	PKG_INSTALL   = INSTALL_ROOT & "lib/m3/pkg"         % packages
	EMACS_INSTALL = INSTALL_ROOT & "lib/elisp"          % emacs lisp code
	MAN_INSTALL   = INSTALL_ROOT & "man"                % man pages
	HTML_INSTALL  = INSTALL_ROOT & "lib/m3/www"         % public hypertext




======================================================================= 106 ===
Date:    Sat, 28 Jan 1995 19:44:42 GMT
From:    leendert@cs.vu.nl (Leendert van Doorn)
Subject: Re: Problems with M3 V3.4 and Solaris 2.3

root@owl.bias.Uni-Bremen.DE (Jochen Skupin) writes:

# At this stage compiling and running of the "hello world" programm works.
# But the compiled packages (Tetris, Cube ...) won't run. They all stop with
# the error (And that what's bothering me.):
# 
# 	***
# 	*** runtime error:
# 	***    Exception "Date.Error" not in RAISES list
# 	***
# 
# 	Abort - core dumped
# 
# I have no clue, what's happening here (I'm wether used to work with Modula3
# nor UNIX nor C :-( ). Does anybody know how to solve this problem?

This has to do with SRC being west of GMT instead of east :-)

The following fixes it:

*** libm3/src/uid/Common/TimeStamp.m3	Fri Jan  6 17:18:50 1995
--- libm3/src/uid/Common/TimeStamp.m3.ORIG	Fri Jan  6 17:08:40 1995
***************
*** 2,9 ****
  (* All rights reserved.                                        *)
  (* See the file COPYRIGHT for a full description.              *)
  (*                                                             *)
! (* Last modified on Fri Jan  6 17:18:05 MET 1994 by leendert   *)
! (*      modified on Tue Aug 24 09:05:29 PDT 1993 by kalsow     *)
  (*      modified on Thu Jul 15 17:33:05 PDT 1993 by swart      *)
  (*      modified on Wed Apr 21 13:15:46 PDT 1993 by mcjones    *)
  (*      modified on Tue Mar  9 15:02:05 PST 1993 by mjordan    *)
--- 2,8 ----
  (* All rights reserved.                                        *)
  (* See the file COPYRIGHT for a full description.              *)
  (*                                                             *)
! (* Last modified on Tue Aug 24 09:05:29 PDT 1993 by kalsow     *)
  (*      modified on Thu Jul 15 17:33:05 PDT 1993 by swart      *)
  (*      modified on Wed Apr 21 13:15:46 PDT 1993 by mcjones    *)
  (*      modified on Tue Mar  9 15:02:05 PST 1993 by mjordan    *)
***************
*** 142,148 ****
  
  PROCEDURE FindEpoch () =
    CONST
!     epochDate = Date.T{1970, Date.Month.Jan, 2, 0, 0, 0, 0, "",
                         Date.WeekDay.Sun};
    <*FATAL Date.Error*>
    BEGIN
--- 141,147 ----
  
  PROCEDURE FindEpoch () =
    CONST
!     epochDate = Date.T{1970, Date.Month.Jan, 1, 0, 0, 0, 0, "",
                         Date.WeekDay.Sun};
    <*FATAL Date.Error*>
    BEGIN


	Leendert

-- 
Leendert van Doorn 			   		<leendert@cs.vu.nl>
Vrije Universiteit / Dept. of Math. & Comp. Sci.	+31 20 4447762
Amoeba project / De Boelelaan 1081A
1081 HV Amsterdam / The Netherlands


======================================================================= 107 ===
Date:    Sun, 29 Jan 1995 02:55:02 GMT
From:    krystof@cs.washington.edu (Krzysztof Zmudzinski)
Subject: WANTED: programs written in Modula 3

I am looking for some interesting (multi-threaded, memory intensive)
programs (source codes) to test my M3 GC port to Alpha.

Krystof




======================================================================= 108 ===
Date:    29 Jan 1995 05:51:06 GMT
From:    ckingsto%hookup.net@mail.hookup.net
Subject: Re: Modula-3 for NT

In <xe44q+9.dharri16@delphi.com>, Dj Harris <dharri16@delphi.com> writes:
>Is there a port of M3 for NT ?
>And where can I get it, if it exists ?
> 
>Thanks, Dj

NT 386 port is available at the ftp site gatekeeper.dec.com in
 /pub/DEC/Modula-3/release3.4 (hope that dir is correct).  Not
a full implementation (networking is missing I think).

CRAIG.


======================================================================= 109 ===
Date:    29 Jan 1995 05:47:17 GMT
From:    ckingsto%hookup.net@mail.hookup.net
Subject: Re: Status of various ports?

In <3g7duj$30d@lucy.cs.columbia.edu>, kraizman@news.cs.columbia.edu (Michael Kr
aizman) writes:
>Sorry to sound like a broken record, but does anyone know the status
>of the modula3 ports to NT and OS/2 and where to get them?
>
>Thanks.
>
>
>Michael Kraizman
>
>----------------------------------------------------------------------
>kraizman@cs.columbia.edu
>-- 
>Michael Kraizman


Work on OS/2 port was delayed a couple of months due to unrelated issues
but work has resumed - sorry, no date available (give me a few weeks)

CRAIG -



======================================================================= 110 ===
Date:    29 Jan 1995 21:50:48 GMT
From:    knechamk@ic.sunysb.edu (Kirk A Nechamkin)
Subject: Help-Modula3 for Linux


Ok,
	Somebody please help, FAST. As a student at Stony Brook
I have grown accustomed to using linux ports of various software
pakacges/languages to do my comp. sci. assignments, rather than
using the schools HP workstations, mainly because they are outdated
and extremely overloaded.

	So I downloaded Modula-3 and installed it...it's sort of working,
it can compile Hello-world. But when I try to run the out-file I get
the message: 'can't find 'libm3.so.3'. I get this message even
when the library file is in the same directory. Also, many of the programs
in the modula3-3.3/bin directory won't run either-giving me the same error
message. 

	Ok, now. Somebody out there must have had this error at some point
and have had to pull their hair out to solve it. Please email
me ANY info on how I can eradicate this error so I can do my 
projects. It would be very appreciated. Thanks.


-Kirk
knechamk@ic.sunysb.edu

Newsgroups: comp.lang.modula3
Subject: Help - Modula3 for Linux
Summary: 
Followup-To: 
Distribution: world
Organization: State University of New York at Stony Brook
Keywords: 



======================================================================= 111 ===
Date:    27 Jan 1995 01:58:33 GMT
From:    bm@shadow.cs.columbia.edu (Blair MacIntyre)
Subject: Macintosh port of M3?

Is anyone working on a mac port of modula-3?  While looking through
the Useful Interfaces document (SRC Report 113), I saw a reference to
Macintosh filename conventions ... it got me wondering about a
possible port of m3.

(It would be nice to be able to work on my laptop).
--
Blair MacIntyre (bm@cs.columbia.edu), Graduate Student (Graphics and UI Lab)

smail: Dept. of Computer Science, 450 Computer Science Building, 500 W 120 St.
       Columbia University, New York, NY 10027


======================================================================= 112 ===
Date:    28 Jan 1995 09:13:07 -0800
From:    rro@Tera.COM (Rod Oldehoeft)
Subject: Re: Request for status on v. 3.4 (SPARC)

In the discussion of the sizes of things, two ideas are being
confused.  The first is the sizes of compilers, libraries and
executables as they reside in disk files.  The second is the
memory-resident size of executable products of the language
implementation.

In some sense, large libraries may only mean that there's a lot
of support for much functionality, should a particular program
actually want to use it.  Sounds like a good thing.

On the other hand, a large memory-resident executable for a
really simple application often is a symptom of an ensemble
of library functions that rely on each other too much.  This
is what I referred to earlier as being common in "young"
implementations.



======================================================================= 113 ===
Date:    29 Jan 1995 20:40:00 +0100
From:    kai@khms.westfalen.de (Kai Henningsen)
Subject: Re: Request for status on v. 3.4 (SPARC)

rro@Tera.COM wrote on 25.01.95 in <3g6vs6$35s@tera.com>:

> If there really is thread software in there, for example, it would be
> disappointing. The idea of minimizing the strength of connection among
> functions is not a new idea, just a good one.  Back to the young
> software point, this is just not on the top of the list for
> implementors.  A commercial motivation would clearly help.

I think the real problem is that there is no support for dividing up  
modules in parts, only some of which get linked in. That, by the way, is  
what makes Borland Pascal or Mac Object Pascal programs small.

As a programmer, you don't want to spend your time figuring out what sort  
of modularization would make for small executables. You want logical  
modularization instead. The system should do the rest. The abovementioned  
cases show it's possible.

Kai
--
Internet: kh@ms.maus.de, kai@khms.westfalen.de
Bang: major_backbone!{ms.maus.de!kh,khms.westfalen.de!kai}

## CrossPoint v3.02 ##


======================================================================= 114 ===
Date:    29 Jan 1995 20:45:00 +0100
From:    kai@khms.westfalen.de (Kai Henningsen)
Subject: Re: Request for status on v. 3.4 (SPARC)

gwyant@cloyd.East.Sun.COM wrote on 25.01.95 in <9501251523.AA23934@cloyd.East.S
un.COM>:

> on. I think that a commercial implementation of M3 could be made smaller by
> having more intimate knowledge of object file formats. I personally don't
> feel that this is something that SRC should be devoting resources to. If you

Correct. The SRC compiler uses gcc code, so the optimal solution would be  
to enhance gcc to do it right, then leverage this for M3.

Kai
--
Internet: kh@ms.maus.de, kai@khms.westfalen.de
Bang: major_backbone!{ms.maus.de!kh,khms.westfalen.de!kai}

## CrossPoint v3.02 ##


======================================================================= 115 ===
Date:    30 Jan 1995 11:18:37 -0500
From:    hendrik@CAM.ORG (Hendrik Boom)
Subject: Re: Modula-3 for OS/2

ckingsto@hookup.net@mail.hookup.net wrote:
: In <DAGENAIS.95Jan17083244@notung.vlsi.polymtl.ca>, dagenais@notung.vlsi.poly
mtl.ca (Michel Dagenais) writes:
: >
: >From the FAQ. The last persons known to be working on such a port were
: >Hendrik Boom hendrick@CAM.ORG and Craig Andrew Kingston 
: >ckingsto@undergrad.math.uwaterloo.ca.
: >--
: >
: >Prof. Michel Dagenais			    dagenais@vlsi.polymtl.ca
: >Dept of Electrical and Computer Eng.
: >Ecole Polytechnique de Montreal		    tel: (514) 340-4029

: Hi Everyone - Craig here.

: I am still continuing to work on the port - just got delayed for a couple of 
months
: because of issues not relating to the port.  Not sure at this time of any dat
es.

: CRAIG
: note: (my email has changed - not longer ckingsto@undergrad.math.uwaterloo.ca
 
: but is now ckingsto@hookup.net)

Hi everyone, Hendrik here.

I too have been delayed by issues not related to the port -- most 
notably a series of total and catastrophic hardware failures.  The 
machine is up and running now (except for the tape backup system :-( ),  
but I am still putting the pieces together, and it will be quite
a while before I get back to modula-3.  When I do it will probably be 
best if I see if Craig needs any help, rather than going it alone.


======================================================================= 116 ===
Date:    Mon, 30 Jan 1995 16:11:37 -0500
From:    douglm@rpi.edu
Subject: Revelations

All below refers to V3.3 on a SPARC.

I have a program built out of a number of components. I think we can ignore
most and concentrate on the part of the structure where:

  Program P includes an interface from package M which includes A from package 
C

A defines a public object to represent the package C. Within C there are a
number of private routines and an interface Apvt which defines further
private fields and methods for the public object. The structure is:

INTERFACE A;
TYPE T <: Public;
  Public = OBJECT
     <fields>
  METHODS
     <Methods>
  END;
END A;
----------------------------
INTERFACE Apvt;
IMPORT A;
TYPE T = A.Public OBJECT
    <Private fields>
  METHODS
    <Private methods>
  END;

REVEAL A.T <: T;          (* Define  A.T <: Apvt.T <: A.Public *)

END Apvt.
----------------------------
MODULE Apvt;
...
REVEAL A.T = T BRANDED "..." OBJECT
  OVERRIDES
  END;
....
END Apvt.

The intention is that only A.T should be visible to users of the package
and the internal methods are restricted to those routines that implement
the package.
These definitions worked previously. I restructured the packages (without
changing the definitions above) making A the only visible interface.
Despite the explicit revalation of A.T in Apvt, when I try to build the
program, I get the message

opaque type never revealed: A.T (...

I guess the revelation of A.T is being hidden in some way. Any ideas?






======================================================================= 117 ===
Date:    30 Jan 1995 09:52:29 -0600
From:    claird@Starbase.NeoSoft.COM (Cameron Laird)
Subject: Re: L'OBJET: A new journal (in French) on object technology.

In article <3gb2bi$20o@crchh327.bnr.ca>,
Jeffrey Fries P865  <pegasus1@bnr.ca> wrote:
		[eighty lines of pointlessly
		included text, among which
		were this summary]
>bertrand@vienna.eiffel.com (Bertrand Meyer) wrote:
>>
>> 
>> [This message describes the launching of a new journal, in French,
>> entirely devoted to object technology.]
			.
			.
			.
>What did ya say ?
>
>huh ?
>

Professor Meyer, please know that you have many
readers who welcomed your announcement.  For my
part, I would only have suggested that you per-
haps expand your cross-posting to include
{alt,misc}.books.technical.  The rudeness of Mr.
Fries' follow-up tells far more about his per-
sonal failings than about the merit of your
notice.

Follow-ups trimmed.
-- 

Cameron Laird		ftp://ftp.neosoft.com/pub/users/claird/home.html
claird@Neosoft.com      +1 713 267 7966
claird@litwin.com       +1 713 996 8546


======================================================================= 118 ===
Date:    Mon, 30 Jan 1995 16:46:52 -0500
From:    gwyant@cloyd.East.Sun.COM (Geoffrey Wyant - Sun Microsystems Labs BOS)
Subject: Re: Request for status on v. 3.4 (SPARC)

	<9501241445.AA22145@cloyd.East.Sun.COM>
	<3g6vs6$35s@tera.com>
	<5emh2nYEcsB@khms.westfalen.de>Cc: m3@src.dec.com
In-Reply-To: <5emh2nYEcsB@khms.westfalen.de>
Distribution: world
X-Received: from suneast.East.Sun.COM by East.Sun.COM (4.1/SMI-4.1)
X-Received: by src-mail.pa.dec.com; id AA07508; Mon, 30 Jan 95 13:55:28 -0800
X-Newsgroups: comp.lang.modula3
X-Content-Length: 1157
X-Received: from cloyd.East.Sun.COM by suneast.East.Sun.COM (5.0/SMI-4.1-900117
)
X-Received: from Sun.COM by inet-gw-2.pa.dec.com (5.65/10Aug94)
X-Received: by cloyd.East.Sun.COM (5.x/SMI-SVR4)
X-Received: from East.Sun.COM (east.East.Sun.COM) by Sun.COM (sun-barr.Sun.COM)
X-Received: by src-news.pa.dec.com; id AA01281; Mon, 30 Jan 95 13:55:30 -0800

Kai Henningsen writes:
 > rro@Tera.COM wrote on 25.01.95 in <3g6vs6$35s@tera.com>:
 > 
 > > If there really is thread software in there, for example, it would be
 > > disappointing. The idea of minimizing the strength of connection among
 > > functions is not a new idea, just a good one.  Back to the young
 > > software point, this is just not on the top of the list for
 > > implementors.  A commercial motivation would clearly help.
 > 
 > I think the real problem is that there is no support for dividing up  
 > modules in parts, only some of which get linked in. That, by the way, is  
 > what makes Borland Pascal or Mac Object Pascal programs small.
 > 
 > As a programmer, you don't want to spend your time figuring out what sort  
 > of modularization would make for small executables. You want logical  
 > modularization instead. The system should do the rest. The abovementioned  
 > cases show it's possible.
 > 

Just remember, Borland Pascal and Mac Object Pascal implement their own
linkers. The SRC implementors made an explicit decision to not implement
an M3-specific linker and instead provide easy portability of the system.

--geoff


======================================================================= 119 ===
Date:    Mon, 30 Jan 1995 15:44:09 GMT
From:    gcorneau@absolu.qc.ca (Gaetan Corneau)
Subject: Re: L'OBJET: A new journal (in French) on object technology.


>> [This message describes the launching of a new journal, in French,
>> entirely devoted to object technology.]
>> 
>>       Une nouvelle publication en langue francaise, la premiere a notre
>> connaissance a etre entierement consacree aux technologies objet, vient
>> d'etre creee:
  
   Snip! Snip!

>> Bertrand Meyer - ISE, Santa Barbara, California
>> 805-685-1006, fax 805-685-6869, <bertrand@eiffel.com>
>> Web home page: http://www.eiffel.com
>> ftp://eiffel.com


>What did ya say ?

>huh ?

Et TOI, qu'as-tu dit? (And YOU, what did you say?)...

Yes: not every people on the planet (or in the universe) speak english: real 
life is not like Star Trek!     ;-)


--------------------------------------------------------------------
 GAETAN CORNEAU                
 Software designer     
        
 Absolu Technologies inc.     Phone:      (418) 650-5516 
 360 Franquet, suite 70       Fax:        (418) 650-0860 
 Quebec Metro High Tech Park  E-Mail:     gcorneau@absolu.qc.ca
 Sainte-Foy, Quebec, G1P 4N3  Compuserve: 73062,3653@compuserve.com 
 Canada                       
--------------------------------------------------------------------


======================================================================= 120 ===
Date:    29 Jan 1995 20:41:43 -0500
From:    bm@news.cs.columbia.edu (Blair MacIntyre)
Subject: Initializing a multidimension array (and possible bug in compiler)

I'm obviously missing something.  How does one write an initialization
expression for a multidimension array?

For example, lets say I have:
---------------------------
INTERFACE GraphicsTypes;

TYPE
  Matrix = ARRAY [0..3], [0..3] OF LONGREAL;
  Vector = ARRAY [0..3] OF LONGREAL;

END GraphicsTypes.
----------------------------
MODULE Test EXPORTS Main;
IMPORT Wr, Stdio, Fmt, Word, GraphicsTypes;

VAR
  rotation_m := GraphicsTypes.Matrix{{0.0, 0.0, 0.0, 0.0}, 
                                     {0.0, 1.0, 0.0, 0.0},
                                     {0.0, 0.0, 1.0, 0.0},
                                     {0.0, 0.0, 0.0, 1.0}};

BEGIN
END Test.
----------------------------

This doesn't work, resulting in a compiler core dump in M3Buf.m3:

----------------------------
m3build
--- building in ../HPPA ---
m3 -w1 -why -g -o Test -F/usr/tmp/qkAAAa18650 
new source -> compiling ../src/Test.m3
"../src/Test.m3", line 6: unexpected type expression


***
*** runtime error:
***    Value out of range
***    file "../src/M3Buf.m3", line 73
***

sh: 18652 Abort(coredump)
*** error code 134 (ignored)

Compilation finished at Sun Jan 29 20:35:44
-------------------------------

Similarly, making the declaration one level:
  rotation_m := GraphicsTypes.Matrix{0.0, 0.0, 0.0, 0.0, 
                                     0.0, 1.0, 0.0, 0.0,
                                     0.0, 0.0, 1.0, 0.0,
                                     0.0, 0.0, 0.0, 1.0};

results in 
---------------------------------
m3build
--- building in ../HPPA ---
m3 -w1 -why -g -o Test -F/usr/tmp/qkAAAa18654 
new source -> compiling ../src/Test.m3
"../src/Test.m3", line 6: too many values specified
"../src/Test.m3", line 6: expression is not assignable to array element
"../src/Test.m3", line 6: expression is not assignable to array element
"../src/Test.m3", line 6: expression is not assignable to array element
"../src/Test.m3", line 6: expression is not assignable to array element
"../src/Test.m3", line 6: expression is not assignable to array element
"../src/Test.m3", line 6: expression is not assignable to array element
"../src/Test.m3", line 6: expression is not assignable to array element
"../src/Test.m3", line 6: expression is not assignable to array element
"../src/Test.m3", line 6: expression is not assignable to array element
"../src/Test.m3", line 6: expression is not assignable to array element
"../src/Test.m3", line 6: expression is not assignable to array element
"../src/Test.m3", line 6: expression is not assignable to array element
"../src/Test.m3", line 6: expression is not assignable to array element
"../src/Test.m3", line 6: expression is not assignable to array element
"../src/Test.m3", line 6: expression is not assignable to array element
"../src/Test.m3", line 6: expression is not assignable to array element
"../src/Test.m3", line 6: warning: not used (rotation_m)
17 errors encountered
compilation failed => not building program "Test"
*** error code 1 (ignored)
-----------------------------------


Thanks for any help.



======================================================================= 121 ===
Date:    31 Jan 1995 16:21:05 GMT
From:    kalsow@src.dec.com (Bill Kalsow)
Subject: Re: Initializing a multidimension array (and possible bug in compiler)

In article <199501300141.UAA02891@shadow.cs.columbia.edu>, bm@news.cs.columbia.
edu (Blair MacIntyre) writes:
> I'm obviously missing something.  How does one write an initialization
> expression for a multidimension array?
> 
> VAR
>   rotation_m := GraphicsTypes.Matrix{{0.0, 0.0, 0.0, 0.0}, 
>                                      {0.0, 1.0, 0.0, 0.0},
>                                      {0.0, 0.0, 1.0, 0.0},
>                                      {0.0, 0.0, 0.0, 1.0}};
> 
> This doesn't work, resulting in a compiler core dump in M3Buf.m3:


Modula-3 requires a type name or expression at the beginning of every
constructor.  In your case, the inner arrays constructors require type
names.  The following should work:

 VAR
   rotation_m := GraphicsTypes.Matrix{
                   GraphicsTypes.Vector{0.0, 0.0, 0.0, 0.0}, 
                   GraphicsTypes.Vector{0.0, 1.0, 0.0, 0.0},
                   GraphicsTypes.Vector{0.0, 0.0, 1.0, 0.0},
                   GraphicsTypes.Vector{0.0, 0.0, 0.0, 1.0}};


 - Bill Kalsow

P.S.  I fixed the bug that caused the compiler crash in M3Buf.  Thanks
for the indirect bug report.


======================================================================= 122 ===
Date:    31 Jan 1995 23:12:05 GMT
From:    kalsow@src.dec.com (Bill Kalsow)
Subject: Re: Revelations

In article <ab52cfb80202100439dc@[128.113.24.157]>, douglm@rpi.edu writes:
> I have a program built out of a number of components. I think we can ignore
> most and concentrate on the part of the structure where:
> 
>   Program P includes an interface from package M which includes A from packag
e C
> 
> A defines a public object to represent the package C. Within C there are a
> number of private routines and an interface Apvt which defines further
> private fields and methods for the public object. The structure is:

I can't be certain from the facts you posted.  My guess is that
no interface or module imports Apvt, so the linker is not including
it.

Since Apvt is providing the full revelation for A.T, I would
have Apvt export A and Apvt.  But, since both interfaces A and
Apvt define a type T, you'll need to shuffle some names.

  - Bill Kalsow



======================================================================= 123 ===
Date:    Tue, 31 Jan 1995 13:45:13 GMT
From:    bwbecker@dragon.uwaterloo.ca (Byron Weber Becker)
Subject: Differences between 3.3 and 3.4

Can someone summarize the differences between version 3.3
and 3.4?  We've got 3.3 running -- what does the pain and
agony of installing 3.4 buy me?  Is it worth it?


=====
Byron Weber Becker                               (519) 888-4567 x4661
Computer Science Lecturer/Advisor        bwbecker@dragon.uwaterloo.ca
University of Waterloo


======================================================================= 124 ===
Date:    Tue, 31 Jan 1995 13:44:01 GMT
From:    bwbecker@dragon.uwaterloo.ca (Byron Weber Becker)
Subject: Re: Initializing a multidimension array (and possible bug in compiler)

In article <199501300141.UAA02891@shadow.cs.columbia.edu>
bm@news.cs.columbia.edu (Blair MacIntyre) writes:

> I'm obviously missing something.  How does one write an initialization
> expression for a multidimension array?
> 
> For example, lets say I have:
> ---------------------------
> INTERFACE GraphicsTypes;
> 
> TYPE
>   Matrix = ARRAY [0..3], [0..3] OF LONGREAL;
>   Vector = ARRAY [0..3] OF LONGREAL;
> 
> END GraphicsTypes.
> ----------------------------
> MODULE Test EXPORTS Main;
> IMPORT Wr, Stdio, Fmt, Word, GraphicsTypes;
> 
> VAR
>   rotation_m := GraphicsTypes.Matrix{{0.0, 0.0, 0.0, 0.0}, 
>                                      {0.0, 1.0, 0.0, 0.0},
>                                      {0.0, 0.0, 1.0, 0.0},
>                                      {0.0, 0.0, 0.0, 1.0}};
> 
> BEGIN
> END Test.
> ----------------------------
> 
> This doesn't work, resulting in a compiler core dump in M3Buf.m3:

Can't comment on the core dump, but I believe the right way to
initialize it is to view Matrix this way:

TYPE
  Vector = ARRAY [0..3] OF LONGREAL;
  Matrix = ARRAY [0..3] OF Vector;    (* Exactly equivilent to 
                                         what you have *)

VAR
  rotation_m := GraphicsTypes.Matrix{Vector{0.0, 0.0, 0.0, 0.0},
                                     Vector{0.0, 1.0, 0.0, 0.0},
                                     Vector{0.0, 0.0, 1.0, 0.0},
                                     Vector{0.0, 0.0, 0.0, 1.0}};

=====
Byron Weber Becker                               (519) 888-4567 x4661
Computer Science Lecturer/Advisor        bwbecker@dragon.uwaterloo.ca
University of Waterloo


======================================================================= 125 ===
Date:    Tue, 31 Jan 1995 20:24:44 GMT
From:    hinsenk@cyclone.ERE.UMontreal.CA (Hinsen Konrad)
Subject: Re: L'OBJET: A new journal (in French) on object technology.

In article <3gluda$nm1@crchh327.bnr.ca> Jeffrey Fries P865 <pegasus1@bnr.ca> wr
ites:

   When in Rome....speak Italian....When in USA, speak English.

Usenet has become quite international. It's not just the USA any more.

--
-------------------------------------------------------------------------------
Konrad Hinsen                     | E-Mail: hinsenk@ere.umontreal.ca
Departement de Chimie             | Tel.: +1-514-343-6111 ext. 3953
Universite de Montreal            | Fax:  +1-514-343-7586
C.P. 6128, succ. A                | Deutsch/Esperanto/English/Nederlands/
Montreal (QC) H3C 3J7             | Francais (phase experimentale)
-------------------------------------------------------------------------------


======================================================================= 127 ===
Date:    31 Jan 1995 20:09:57 GMT
From:    jhoward@solar.sky.net (John Howard)
Subject: Abstract Data Types book

I am looking for a book published by Springer-Verlag which is a 
comprehensive compendium of abstract data types.  Their were two authors 
for it.  The title and ISBN number elude me.  This info was posted 
recently in one of the comp.*.* groups but I lost it.  Can anyone help?


======================================================================= 128 ===
Date:    31 Jan 1995 18:09:46 GMT
From:    Jeffrey Fries P865 <pegasus1@bnr.ca>
Subject: Re: L'OBJET: A new journal (in French) on object technology.

gcorneau@absolu.qc.ca (Gaetan Corneau) wrote:
>
> 
> >> [This message describes the launching of a new journal, in French,
> >> entirely devoted to object technology.]
> >> 
> >>       Une nouvelle publication en langue francaise, la premiere a notre
> >> connaissance a etre entierement consacree aux technologies objet, vient
> >> d'etre creee:
>   
>    Snip! Snip!
> 
> >> Bertrand Meyer - ISE, Santa Barbara, California
> >> 805-685-1006, fax 805-685-6869, <bertrand@eiffel.com>
> >> Web home page: http://www.eiffel.com
> >> ftp://eiffel.com
> 
> 
> >What did ya say ?
> 
> >huh ?
> 
> Et TOI, qu'as-tu dit? (And YOU, what did you say?)...
> 
> Yes: not every people on the planet (or in the universe) speak english: real 
> life is not like Star Trek!     ;-)
> 
> 
> --------------------------------------------------------------------
>  GAETAN CORNEAU                
>  Software designer     
>         
>  Absolu Technologies inc.     Phone:      (418) 650-5516 
>  360 Franquet, suite 70       Fax:        (418) 650-0860 
>  Quebec Metro High Tech Park  E-Mail:     gcorneau@absolu.qc.ca
>  Sainte-Foy, Quebec, G1P 4N3  Compuserve: 73062,3653@compuserve.com 
>  Canada                       
> --------------------------------------------------------------------

When in Rome....speak Italian....When in USA, speak English.

Rude...my butt!



======================================================================= 129 ===
Date:    29 Jan 1995 16:48:11 GMT
From:    Quentin Stafford-Fraser <fraser@europarc.xerox.com>
Subject: Re: Modula-3 for NT

Is anyone able to make NT binaries available?

Quentin


======================================================================= 149 ===
Date:    31 Jan 1995 03:49:30 GMT
From:    bm@stieglitz.cs.columbia.edu (Blair MacIntyre)
Subject: YASQ: any hints as to why @M3showthread might now work?

showthread is at least running and trying to open the display (if I
take away xhost permission, it fails (and prints out something to that
effect).

When xhost permission is there, no window appears and the program
doesn't start (the program runs fine without the @M3showthread).

BTW, YASQ is "yet another stupid question".  

This is on the SPARC implementation, v3.4, with a remote display
(either an HP or an SGI).
--
Blair MacIntyre (bm@cs.columbia.edu), Graduate Student (Graphics and UI Lab)

smail: Dept. of Computer Science, 450 Computer Science Building, 500 W 120 St.
       Columbia University, New York, NY 10027


======================================================================= 169 ===
Date:    31 Jan 1995 01:07:48 GMT
From:    ilu-core@parc.xerox.com
Subject: ILU 1.7 now available

ILU 1.7, which fixes many bugs in ILU 1.6, and provides new support
for the programming language Python, is now available via the
links from ftp://ftp.parc.xerox.com/pub/ilu/ilu.html, or directly
as ftp://ftp.parc.xerox.com/pub/ilu/1.7/ilu-1.7.tar.gz.

ILU is a system for defining and using language-independent
object-oriented interfaces.  It can be used to define and implement
the API's for reusable software libraries.  It is also, due to its
implementation design, a ``distributed object'' system, which can be
used to interlink code written in either C, C++, Modula-3, Common
Lisp, or Python.  It can be used with any mix of these languages as an
object-oriented RPC system to build client-server systems.  It can
understand interface descriptions written in OMG IDL ("CORBA" IDL),
and produces CORBA-compliant language mappings for ANSI C.  Xerox is
providing it free of charge for any use, including commercial
products.
--
 Bill Janssen  <janssen@parc.xerox.com> (415) 812-4763  FAX: (415) 812-4777
 Xerox Palo Alto Research Center, 3333 Coyote Hill Rd, Palo Alto, CA  94304
 URL:  ftp://parcftp.parc.xerox.com/pub/ilu/misc/janssen.html


