Page Numbers: Yes X: 558 pt Y: 0.5" Margins: Top: 1.25" Bottom: 1.5" Columns: 1 Edge Margin: 1.0" Heading: File: cedar-style.bravo April 22, 1980 The Cedar Style Sheet Names Capitalization (C1) The first letter of a name is capital if it identifies a module, procedure, signal, or type, otherwise the first letter is lower-case. Fugleman, SomeProc, ObjectSupport (C1b) Not allowed to declare two identifiers that differ only by case shifts, except for foo:Foo (C2) Each imbedded word of a multi-word name has its first letter capitalized. field1, anotherFm, aLongName Qualification (Q1) Use fully qualified names, with few exceptions: OPENing the definitions module that a program module implements. OPENing an interface in a (small) scope within which items from the interface are used a lot. or, provided that there is a USING clause in the directory section for the interface. (Q2) It is usually better to use the "OPEN alternateName: xxx" form with a short alternateName than to use the form "OPEN xxx". (Q3) No opens unless expression is an interface type (Q4) use the "WITH alternateName: xxx SELECT ..." form with a short alternateName instead of the form "WITH xxx SELECT ...". Module Naming (M1) DEFINITIONS modules have no "Defs" suffix on their names; PROGRAM module names have suffix "Impl"; no suffix on CONFIGURATION module names; e.g., ObjectSupport.mesa -- DEFINITIONS module ClassFugleman.mesa -- DEFINITIONS module for object interface ObjectSupportImpl.mesa -- PROGRAM module CedarSupport.config -- CONFIGURATION module (M1a) Impl is only required if definitions file name conflicts (M1b) Name of a config file should not include "Config" as a suffix, but should use it as an extension; e.g., FooConfig.config NO Foo.config YES Types (Claim) It is almost always better to name a type than to define an anonymous one, especially in definitions modules: DeckIndex: TYPE = [0..52); CardDeck: TYPE = ARRAY DeckIndex OF Card; -- YES CardDeck: TYPE = ARRAY [0..52) OF Card; -- NO Interval Types [0..upperLimit) -- preferred form FOR i IN [0..n) DO IF a[i]=a[n] THEN . . . ENDLOOP; Record types, constructors, and extractors (P1) Keyword argument lists, constructors, and extractors single-argument procs - not needed two- or more-argument procedures - it's a good idea to use keyword constructors for the argument, especially if any two of the parameters have equivalent types (P2) include keywords on procedure result fields in defs (if more than one) SIGNALs (S0) Don't use ENDCASE to handle specific cases; either use it to handle "all other cases" or to generate an ERROR In DEFINITIONS modules (S1) Each DEFINITIONS module defines at most one SIGNAL which passes a single argument detailing the reason for the signal. The argument is a value of an enumerated type. E.g., HashTableProblem: SIGNAL [reason: ErrorCode]; ErrorCode: TYPE = {damaged, bug, tableFull}; (S1a) May be a small set of signals such as in (S1) (S1b) Locally defined signals are okay. (S1d) (Ed's proposal) (1) declare ERRORs as ERRORs (2) each resumable signal should get a different name (since these are rare). (S2) Each procedure in an interface that generates signals or errors should have stylized comments indicating which errors or signals it generates and what RESUME means for the signals. E.g., FindItem: PROCEDURE[k: Key] RETURNS [v: Value, found: BOOLEAN]; -- ERRORs: HashTableProblem[damaged] -- SIGNALs: HashTableProblem[tableFull] -- tries again if resumed (S2b) When generating a SIGNAL or ERROR, one must write SIGNAL foo or "ERROR foo", not just "foo". In PROGRAM modules (S3) Don't let errors or signals that are "part of" the interfaces of invoked routines pass by: transform them into ones that are part of your interface (i.e., insulate your clients from details of your implementation). (S4) Avoid using "ERROR;" Program layout We need a pretty printer Mesa 6: SDD will supply one Cedar: Warren will supply one Extra information: (R1) extra info in first line (+ file name) (passed) (R2) End of file: Change Log for keeping track of what has happened to a module and for learning its history. (R2a) paragraph of global info about program just in front of edit log (R3) don't use bravo formatting (must have passed, but nothing in my notes) Where to keep things [Ivy]ProjectName>Release Example: [Ivy]Database>1.1 [Ivy]Support>Release -- support software everyone will need -- comes as a configuration: CedarSupport.config (.bcd) Library: [Ivy]Library>Release -- talk to Warren if you have something to submit. Documentation on [Ivy]Library>* -- FILE: ClassFugleman.mesa -- Last Edited by Mitchell, March 27, 1980 9:22 AM ClassFugleman: DEFINITIONS = BEGIN NewStdFugleman: PROCEDURE RETURNS [Fugleman]; -- Each implementation of class Fugleman will, in general, have its own -- New procedure, with parameters specific to that implementation. -- There is, however, often a "standard" implementation for a class, -- and it seems reasonable to put the definition of its New procedure -- here with the definition of the class. Fugleman: TYPE = POINTER TO POINTER TO READONLY FuglemanProcs; FuglemanProcs: TYPE = MACHINE DEPENDENT RECORD [ Release: PROCEDURE [Self: Fugleman] RETURNS [nilFugleman: Fugleman], Print: PROCEDURE [Self: Fugleman], Check: PROCEDURE [Self: Fugleman], SomeProc: PROCEDURE [Self: Fugleman, otherArgument: CARDINAL] RETURNS [CARDINAL] ]; END. This is a template for defining the interface for a class, Fugleman, of objects. It provides for multiple, coexisting implementations of the class. The file FuglemanClient.mesa shows how a client program can create instances of the objects of this class, and the file FuglemanImpl.mesa is a template for an implementation of the class. Change Log Created by Mitchell: March 17, 1980 11:00 AM This is a template for interim Cedar object interfaces. It shows what one would write to define the interface for a class FugleMan of objects with operations Release, Print, Check, and SomeProc Changed by Mitchell: DateTime DescriptionOfChange -- FILE: FuglemanClient.mesa -- Last Edited by Mitchell, March 27, 1980 9:23 AM DIRECTORY ClassFugleman: FROM "ClassFugleman"; FuglemanClient: PROGRAM IMPORTS fugles: ClassFugleman = BEGIN SillyTest: PUBLIC PROCEDURE = -- a nonsense program to show how clients invoke operations on objects implemented this way BEGIN fm: fugles.Fugleman = fugles.NewFugleman[]; anotherFm: fugles.Fugleman = fugles.NewFugleman[]; x: CARDINAL _ 1; fm.Check[fm]; -- check the object IF fm=anotherFm THEN ERROR; -- should get unique objects IF fm.SomeProc[fm, 1] = anotherFm.SomeProc[anotherFm, 2] THEN x_2; END; END. -- FuglemanClient This is an example intended only to show syntactically how client programs create object instances, invoke operations on them and catch signals that those operations might generate. The files ClassFugleman.mesa and FuglemanImpl.mesa contain the definitions of the object interface used here and a sample implementation of it, respectively. Change Log Created by YourName: DateTime DescriptionOfChange Changed by YourName: DateTime DescriptionOfChange -- FILE: FuglemanImpl.mesa -- Last Edited by Mitchell, March 17, 1980 11:33 AM DIRECTORY ObjectSupport: FROM "ObjectSupport", ClassFugleman: FROM "ClassFugleman"; FuglemanStdImpl: PROGRAM IMPORTS ObjSupp: ObjectSupport EXPORTS ClassFugleman = BEGIN OPEN ClassFugleman; -- implementation types CFugleman: TYPE = POINTER TO CFinger; -- concrete form of the object CFinger: TYPE = MACHINE DEPENDENT RECORD [procs: POINTER TO FuglemanProcs, data: POINTER TO FuglemanData]; FuglemanData: TYPE = RECORD [ count: CARDINAL, flag: BOOLEAN _ TRUE, mumble: INTEGER ]; Procedures: FuglemanProcs _ -- this is type-checked by the compiler [Release: Release, Print: Print, Check: Check, SomeProc: SomeProc]; AbstractToRep: PROCEDURE[Self: Fugleman] RETURNS [POINTER TO FuglemanData] = INLINE BEGIN RETURN[LOOPHOLE[Self, CFugleman].data] END; RepToAbstract: PROCEDURE[rep: CFugleman] RETURNS [Fugleman] = INLINE BEGIN RETURN[LOOPHOLE[rep, Fugleman]] END; -- a sample New procedure for creating a Fugleman object NewStdFugleman: PUBLIC PROCEDURE RETURNS [Fugleman] = BEGIN cFugleman: CFugleman _ ObjSupp.AllocateObject[ procs: @Procedures, size: SIZE[FuglemanData]]; cFugleman.data^ _ [count: 5, mumble: -10]; RETURN[RepToAbstract[cFugleman]]; END; -- Operations on a Fugleman Release: PROCEDURE [Self: Fugleman] RETURNS [nilFugleman: Fugleman] = BEGIN RETURN[ObjSupp.FreeObject[Self]]; END; Print: PROCEDURE [Self: Fugleman] = BEGIN d: CFugleman = AbstractToRep[Self]; -- refer to "Self.count" as "d.count" END; Check: PROCEDURE [Self: Fugleman] = BEGIN d: CFugleman = AbstractToRep[Self]; IF d.count>100 OR d.mumble<0 AND NOT d.flag THEN ERROR; -- example only END; SomeProc: PROCEDURE [Self: Fugleman, otherArgument: CARDINAL] RETURNS [CARDINAL] = BEGIN d: CFugleman = AbstractToRep[Self]; IF otherArgument>100 THEN otherArgument _ 100; d.count _ otherArgument; END; END. This is a template for an implementation of the class of objects defined by ClassFugleman.mesa. There may be more than one implementation of this same class. This method of providing objects is intended for use until Cedar/Mesa has sufficient language facilities to avoid the LOOPHOLEs needed here. In any case, no client programs will have to change when this occurs. An example of a client program can be found in FuglemanClient.mesa. Change Log Created by YourName: DateTime DescriptionOfChange Changed by YourName: DateTime DescriptionOfChange -- FILE: ClassFugleman.mesa -- Last Edited by Mitchell, March 27, 1980 9:22 AM ClassFugleman: DEFINITIONS = BEGIN NewStdFugleman: PROCEDURE RETURNS [Fugleman]; -- Each implementation of class Fugleman will, in general, have its own -- New procedure, with parameters specific to that implementation. -- There is, however, often a "standard" implementation for a class, -- and it seems reasonable to put the definition of its New procedure -- here with the definition of the class. Fugleman: TYPE = POINTER TO POINTER TO READONLY FuglemanProcs; FuglemanProcs: TYPE = MACHINE DEPENDENT RECORD [ Release: PROCEDURE [Self: Fugleman] RETURNS [nilFugleman: Fugleman], Print: PROCEDURE [Self: Fugleman], Check: PROCEDURE [Self: Fugleman], -- ERRORS: Problem[damaged] SomeProc: PROCEDURE [Self: Fugleman, otherArgument: CARDINAL] RETURNS [CARDINAL] -- SIGNALS: Problem[argumentOutOfRange] -- uses max allowed value for otherArgument if resumed ]; Problem: SIGNAL[reason: ErrorCode]; ErrorCode: TYPE = {damaged,implementationBug, argumentOutOfRange}; END. This is a template for defining the interface for a class, Fugleman, of objects. It provides for multiple, coexisting implementations of the class. The file FuglemanClient.mesa shows how a client program can create instances of the objects of this class, and the file FuglemanImpl.mesa is a template for an implementation of the class. Change Log Created by Mitchell: March 17, 1980 11:00 AM This is a template for interim Cedar object interfaces. It shows what one would write to define the interface for a class FugleMan of objects with operations Release, Print, Check, and SomeProc Changed by Mitchell: DateTime DescriptionOfChange -- FILE: FuglemanClient.mesa -- Last Edited by Mitchell, March 27, 1980 9:23 AM DIRECTORY ClassFugleman: FROM "ClassFugleman"; FuglemanClient: PROGRAM IMPORTS fugles: ClassFugleman = BEGIN SillyTest: PUBLIC PROCEDURE = -- a nonsense program to show how clients invoke operations on objects implemented this way BEGIN fm: fugles.Fugleman = fugles.NewFugleman[]; anotherFm: fugles.Fugleman = fugles.NewFugleman[]; x: CARDINAL _ 1; fm.Check[fm ! fugles.Problem => ERROR]; -- check the object IF fm=anotherFm THEN ERROR; -- should get unique objects IF fm.SomeProc[fm, 1] = anotherFm.SomeProc[anotherFm, 2] THEN x_2; END; END. -- FuglemanClient This is an example intended only to show syntactically how client programs create object instances, invoke operations on them and catch signals that those operations might generate. The files ClassFugleman.mesa and FuglemanImpl.mesa contain the definitions of the object interface used here and a sample implementation of it, respectively. Change Log Created by YourName: DateTime DescriptionOfChange Changed by YourName: DateTime DescriptionOfChange -- FILE: ClassFuglemanImpl.mesa -- Last Edited by Mitchell, March 27, 1980 11:24 AM DIRECTORY ClassFugleman: FROM "ClassFugleman"; ClassFuglemanImpl: PROGRAM EXPORTS ClassFugleman = BEGIN OPEN ClassFugleman; Problem: SIGNAL[reason: ErrorCode] = CODE; END. This is a template for a class implementation for ClassFugleman.mesa. Its only purpose is to provide a "home" for any SIGNALs defined in ClassFugleman.mesa as one does not want different implementations to provide different actual SIGNALs for them. Change Log Created by YourName: DateTime DescriptionOfChange Changed by YourName: DateTime DescriptionOfChange -- FILE: FuglemanImpl.mesa -- Last Edited by Mitchell, March 17, 1980 11:33 AM DIRECTORY ObjectSupport: FROM "ObjectSupport", ClassFugleman: FROM "ClassFugleman"; FuglemanStdImpl: PROGRAM IMPORTS ObjSupp: ObjectSupport EXPORTS ClassFugleman = BEGIN OPEN ClassFugleman; -- implementation types CFugleman: TYPE = POINTER TO CFinger; -- concrete form of the object CFinger: TYPE = MACHINE DEPENDENT RECORD [procs: POINTER TO FuglemanProcs, data: POINTER TO FuglemanData]; FuglemanData: TYPE = RECORD [ count: CARDINAL, flag: BOOLEAN _ TRUE, mumble: INTEGER ]; Procedures: FuglemanProcs _ -- this is type-checked by the compiler [Release: Release, Print: Print, Check: Check, SomeProc: SomeProc]; AbstractToRep: PROCEDURE[Self: Fugleman] RETURNS [POINTER TO FuglemanData] = INLINE BEGIN RETURN[LOOPHOLE[Self, CFugleman].data] END; RepToAbstract: PROCEDURE[rep: CFugleman] RETURNS [Fugleman] = INLINE BEGIN RETURN[LOOPHOLE[rep, Fugleman]] END; -- a sample New procedure for creating a Fugleman object NewStdFugleman: PUBLIC PROCEDURE RETURNS [Fugleman] = BEGIN cFugleman: CFugleman _ ObjSupp.AllocateObject[ procs: @Procedures, size: SIZE[FuglemanData]]; cFugleman.data^ _ [count: 5, mumble: -10]; RETURN[RepToAbstract[cFugleman]]; END; -- Operations on a Fugleman Release: PROCEDURE [Self: Fugleman] RETURNS [nilFugleman: Fugleman] = BEGIN RETURN[ObjSupp.FreeObject[Self]]; END; Print: PROCEDURE [Self: Fugleman] = BEGIN d: CFugleman = AbstractToRep[Self]; -- refer to "Self.count" as "d.count" END; Check: PROCEDURE [Self: Fugleman] = -- ERRORS: Problem[damaged] BEGIN d: CFugleman = AbstractToRep[Self]; IF d.count>100 OR d.mumble<0 AND NOT d.flag THEN ERROR Problem[damaged]; -- example only END; SomeProc: PROCEDURE [Self: Fugleman, otherArgument: CARDINAL] RETURNS [CARDINAL] = -- SIGNALS: Problem[argumentOutOfRange] -- uses max allowed value for otherArgument if resumed BEGIN d: CFugleman = AbstractToRep[Self]; IF otherArgument>100 THEN BEGIN SIGNAL Problem[argumentOutOfRange]; otherArgument _ 100; END; d.count _ otherArgument; END; END. This is a template for an implementation of the class of objects defined by ClassFugleman.mesa. There may be more than one implementation of this same class. This method of providing objects is intended for use until Cedar/Mesa has sufficient language facilities to avoid the LOOPHOLEs needed here. In any case, no client programs will have to change when this occurs. An example of a client program can be found in FuglemanClient.mesa. Change Log Created by YourName: DateTime DescriptionOfChange Changed by YourName: DateTime DescriptionOfChange