Draft on: [Indigo]Language>CedarStyle.doc, press Release on: [Indigo]Documentation>CedarStyle.doc, press Last edited: by Mitchell, June 5, 1982 3:42 pm; by Horning, June 9, 1982 5:05 pm Stylizing Cedar Programs Introduction styl9ize tr.v. -ized, -izing, -izes. 1. To subordinate verisimilitude to principles of design in the representation of. 2. To represent conventionally; conventionalize. Well, maybe we don't want to "subordinate verisimilitude to principles of design," but using some set of reasonable conventions in Cedar programs probably does have value. The conventions presented here have been generally agreed upon by the Cedar programming community and represent current normal practice. However, they are not hard and fast rules, and there can be good and compelling reasons for not following some convention in a particular instance. Nevertheless, to the extent that we all normally follow them, it will help us in reading (and therefore in modifying) one anothers' programs. This section has two major parts: The first consists of a set of conventions for constructing Cedar identifiers according to their intended uses, for constructing types, for declaring and using SIGNALs and ERRORs, for documentation embedded in modules, for program layout (indentation, etc.), and for object-oriented programming. The second part consists of a set of skeletal programs that employ and exemplify these conventions. In the first part, each convention is given as a short rule followed by some examples of its application. In the examples, the parts that illustrate the rule are highlighted like this. Names Capitalization Capitalize the first letter of a name if it identifies a module, procedure, signal, or type, otherwise the first letter is lower-case: Fugleman: DEFINITIONS = ... Factorial: PROC[i: INT] RETURNS [INT]; Complex: TYPE = RECORD[real, imag: REAL]; NarrowRefFault: ERROR; Capitalize the first letter of each embedded word of a multi-word name: NarrowRefFault: ERROR; ComplexSet: TYPE = LIST OF Complex; aSet: ComplexSet _ CONS[Complex[real: 1.0, imag: 0.0], NIL]; Case shift alone should not be used to distinguish identifiers. There is a single class of exceptions: if one has a type, Foo, it is okay to declare a variable of that type as foo: badID, badId, bADid, BADid: INT -- BAD! complex: Complex; -- acceptable c: Complex; -- acceptable Qualification Identifiers from interfaces should be qualified by their interface names or abbreviations for them: DIRECTORY IOStream, Process, Rope, UserExec; SimpleExample: MONITOR IMPORTS IO: IOStream, Process, R: Rope, UserExec = . . . ReverseName: UserExec.CommandProc = BEGIN . . . END; execStream: IO.Handle; Renaming an interface in the IMPORTS clause is perfectly good practice, provided that you don't use both names in the program. SimpleExample: MONITOR IMPORTS IO: IOStream, Process, R: Rope, UserExec = . . . execStream: IO.Handle; backwordsName _ backwordsName.Cat[R.FromChar[R.Upper[userName.Fetch[i]]]]; Qualified OPEN, i.e., the "OPEN abbreviation: name" form should be used instead of the unqualified "OPEN name" form. Unqualified OPEN is acceptable over the scope of an entire PROGRAM module only for the DEFINITIONS module that it exports. It is also okay to OPEN any interface over a limited scope (e.g., a procedure or a block) within which identifiers from that interface are used heavily. It is never okay to unqualifiedly open anything except an interface. Module Naming All module file names have the extension ".mesa". ObjectSupport.mesa ObjectSupportImpl.mesa ListSortRef.mesa SimpleExample.mesa A DEFINITIONS module does not need any standard suffix on its name. ObjectSupport: DEFINITIONS = . . . ListSortRef: DEFINITIONS = . . . Rope: DEFINITIONS = . . . A PROGRAM/MONITOR module name should have the suffix "Impl" if its name without the suffix would conflict with the name of an exported DEFINITIONS module. ObjectSupportImpl: PROGRAM -- name would conflict with ObjectSupport without Impl EXPORTS ObjectSupport = . . . ObjectMachinery: PROGRAM -- name doesn't conflict with ObjectSupport EXPORTS ObjectSupport = . . . FUN: PROGRAM = -- name conflicts with nothing since it exports nothing CONFIGURATION modules have no common suffix on their names. Rigging: CONFIGURATION EXPORTS Rope = . . . Spy: CONFIGURATION EXPORTS SpyOps = . . . Compiler: CONFIGURATION EXPORTS ExecOps, CompilerOps = . . . A CONFIGURATION file name should have the extension ".config". Rigging.config Spy.config Compiler.config Types Name types rather than defining anonymous types, especially in definitions modules: DeckIndex: TYPE = [0..52); -- YES CardDeck: TYPE = ARRAY DeckIndex OF Card; CardDeck: TYPE = ARRAY [0..52) OF Card; -- NO Interval types with closed lower bounds and open upper bounds are preferred: [0..upperLimit) -- preferred form FOR i IN [0..n) DO IF a[i]=a[n] THEN . . . ENDLOOP; Positional notation for argument lists, record constructors, and extractors is preferred if there is just a single argument or component. It is acceptable if there are multiple components all of different types: ViewerTools.SetSelection[handle.fact.input]; -- force the selection execStream.PutF["Your user name backwards is: %g\n", IO.rope[backwordsName]]; The keyword form for argument lists, record constructors, and extractors is preferred when there are two or more constituents, especially if any have equivalent types. It is also preferred when most components are being defaulted and only a few given values: context.DrawBox[ Box[xmin: 0, ymin: 0, xmax: data.value, ymax: self.ch]]; Menus.AppendMenuEntry[ menu: my.outer.menu, -- the outer container's menu (already defaulted) name: "MyMenuEntry", -- name of the command proc: MyMenuProc, -- proc associated with command fork: TRUE, -- causes a new process to be forked & detached on invocation copy: TRUE ]; -- make this a new menu (i.e. don't modify the default menu) [in: in, out: out] _ IO.CreateTTYStreams[title]; R.Compare[s1: rope, s2: NARROW[r2, ROPE], case: TRUE] NEW[ViewerClasses.ViewerClassRec _ [paint: PaintGraph]]; Named procedure result fields are preferred, especially if there is more than one: CreateBarGraph: PROC [x, y, w, h: INT, parent: ViewerClasses.Viewer, fullScale: REAL] RETURNS [barGraph: ViewerClasses.Viewer] FindItem: PROCEDURE[k: Key] RETURNS [v: Value, found: BOOLEAN]; Exceptions: SIGNALs and ERRORs General ENDCASE should be used to generate an ERROR or to handle "all other cases", but not to handle specific cases Use SIGNAL or ERROR when generating a SIGNAL or ERROR; e.g., write "SIGNAL foo" or "ERROR foo", not just "foo". Avoid using the anonymous ERROR. Locally defined signals that don't escape out of an abstraction are okay. In DEFINITIONS modules Declare ERRORs as ERRORs Use a different name for each resumable SIGNAL (since these are rare). Use stylized comments with each procedure in an interface that generates exceptions indicating which exceptions it generates and what happens if a given SIGNAL is RESUMEd: FindItem: PROC[k: Key] RETURNS [v: Value, found: BOOLEAN]; -- ERRORs: HashTableDamaged -- SIGNALs: HashTableProblem[tableFull]: tries again if resumed In PROGRAM modules Only exceptions that are part of the abstraction should emanate from a module. Don't let exceptions that are "part of" the interfaces of invoked routines escape: transform them into ones that are part of your interface (i.e., insulate your clients from details of your implementation). In-module documentation: The first two lines of a Mesa source module should be comments, one giving the file name for the module, and the other giving the name of the person who last edited it and when she/he did so. -- FILE: OnlineMergeSortRefImpl.mesa -- Last Edited by MBrown on March 9, 1982 5:02 pm Immediately following each procedure declaration in a definitions module should be a brief comment, providing the information most useful to a potential client, who may be reading the listing, or querying via the User Exec. Sort: PROC [itemList: LIST OF Item, compareProc: PROC[Item, Item] RETURNS [Comparison]] RETURNS[LIST OF Item]; -- Destructive sort of itemList; returns sorted list containing same items. -- Order of equal items is not preserved. Keep a CHANGE LOG at the end of each source module for keeping track of who first created the module, who has changed it, why it was changed, and when. CHANGE LOG Created by MBrown on 21-Apr-81 13:26:10 Changed by MBrown on 19-Aug-81 15:14:34 -- CedarString -> Rope (used only in Compare.) Changed by MBrown on 23-Aug-81 17:45:12 -- Fix bug in sorting NIL. Changed by MBrown on 10-Dec-81 9:57:58 -- Cosmetic changes: ROPE, INT. Changed by MBrown on March 9, 1982 5:03 pm -- Use a bounded array in local frame instead of consing up a list of lists on each call. Even for a 32 bit address space, this is only 60 words of array in the frame. Program layout Use Mesa.abbreviations The Fuglemen This section consists of a set of skeletal programs, Fugleman, FuglemanImpl, and FuglemanClient, that employ and exemplify the conventions expounded in the above style discussion. The name Fugleman comes from the following definition: fu9gle9man n., pl. -men. 1. Archaic. A soldier who serves as a guide and model for his company. 2. A leader; especially a religious leader. And, Lord knows, there is no more religious issue than one's favorite programming style. -- FILE: Fugleman.mesa -- Last Edited by Horning, June 7, 1982 2:55 pm Fugleman: DEFINITIONS = BEGIN Handle: TYPE = REF Rep; Rep: TYPE; -- opaque type for the representation of the object FugleFailure: ERROR; NewFugleman: PROCEDURE [RETURNS [Handle]; -- Makes a new Fugleman object Print: PROCEDURE [h: Handle]; Check: PROCEDURE [h: Handle]; -- ERRORs: FugleFailure -- Returns normally if Fugleman object OK SomeProc: PROCEDURE [h: Handle, otherArgument: INT] RETURNS [INT]; -- Comment goes here saying what it does 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, June 4, 1982 3:34 pm -- Convert to present Cedar conventions Changed by Horning, June 7, 1982 2:55 pm -- Use templates from Mesa.abbreviations Changed by Name, DateAndTime -- PurposeOfChange -- FILE: FuglemanClient.mesa -- Last Edited by Horning, June 8, 1982 2:10 pm DIRECTORY Fugleman USING [Handle, NewFugleman, Check, SomeProc, FugleFailure]; FuglemanClient: PROGRAM IMPORTS fugles: Fugleman = BEGIN SillyTestError: ERROR; SillyTest: PUBLIC PROCEDURE = { -- a nonsense program to show how clients invoke operations on objects implemented this way fm: fugles.Handle = fugles.NewFugleman[]; anotherFm: fugles.Handle = fugles.NewFugleman[]; x: INT _ 1; fm.Check[ ! fugles.FugleFailure => ERROR SillyTestError]; -- check the object, convert error IF fm=anotherFm THEN ERROR SillyTestError; -- should get unique objects IF fm.SomeProc[1] = anotherFm.SomeProc[2] THEN x_2; }; 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 Fugleman.mesa and FuglemanImpl.mesa contain the definitions of the object interface used here and a sample implementation of it, respectively. CHANGE LOG Created by Mitchell, March 27, 1980 9:23 AM Produce exemplary template Changed by Horning: June 7, 1982 2:58 pm Cosmetic changes for conformance with current recommendations Changed by Horning: June 8, 1982 2:10 pm Insert CEDAR prefix Changed by YourName: DateTime DescriptionOfChange -- FILE: FuglemanImpl.mesa -- Last Edited by Horning, June 8, 1982 2:15 pm DIRECTORY Fugleman; FuglemanStdImpl: PROGRAM IMPORTS Fugleman EXPORTS Fugleman = BEGIN OPEN Fugleman; -- implementation types Handle: TYPE = REF Rep; -- declare the concrete type locally Rep: PUBLIC TYPE = RECORD[ count: INT, flag: BOOLEAN _ TRUE, mumble: INT]; NewFugleman: PUBLIC PROCEDURE RETURNS [Handle] = { RETURN [NEW[Rep _ [count: 5, mumble: -10]]]; }; -- Operations on a Fugleman Print: PUBLIC PROCEDURE [h: Handle] = { . . . -- some body would go here }; Check: PUBLIC PROCEDURE [h: Handle] = { IF h.count>100 OR h.mumble<0 AND NOT h.flag THEN ERROR Fugleman.FugleFailure; -- example only }; SomeProc: PUBLIC PROCEDURE [h: Handle, otherArgument: INT] RETURNS [r: INT] = { IF otherArgument>100 THEN otherArgument _ 100; h.count _ otherArgument; r _ 17; }; END. -- FuglemanStdImpl This is a template for an implementation of the class of objects defined by Fugleman.mesa. There may be more than one implementation of this same class. An example of a client program can be found in FuglemanClient.mesa. CHANGE LOG Created by Mitchell: March 17, 1980 11:33 AM Exemplary template Changed by Horning: June 7, 1982 6:17 pm Use Mesa.abbreviations Changed by Horning: June 8, 1982 2:15 pm Fix the use of the exported opaque type, add CEDAR prefix Changed by YourName: DateTime DescriptionOfChange Ê}–"Cedardoc" style˜Iclosešœ;˜;Kšœ>˜>KšœP˜PItitle˜section˜ JšÏbÏmœÏiœœœœœRœ.˜ªJšœ¬˜¬JšœÇŸœ]˜¬JšœÃÏsœ œÛ˜¯Jšœ£œ˜¹—šœ˜ssection˜defšŸ%œa˜†J– "cedar" stylešœÏk œ˜J– "cedar" styleš œ˜&J– "cedar" stylešœ¡œ¡œ ¡œ˜)J– "cedar" stylešœ¡œ˜—šŸ1œ˜GJ– "cedar" stylešœ¡œ˜J– "cedar" styleš œ¡œ¡œ ˜#J– "cedar" stylešœ œ¡œ ¡œ˜<—šŸ>œ<Ÿœ3Ÿœ˜´J– "cedar" stylešœ¡œ˜(J– "cedar" stylešœ˜&J– "cedar" styleš œ˜#——˜ šŸ/œ4˜c– "Cedar" styleš¡ ˜ Jšœ"˜"—– "Cedar" stylešœ¡œ˜Jš¡œ.˜5J– "cedar" styleš˜J– "cedar" stylešœ œ¡¡œ˜5J– "cedar" stylešœ œ˜——šŸÐikŸœS˜~– "Cedar" stylešœ¡œ˜Jš¡œ œ œ˜5J– "cedar" styleš˜J– "cedar" stylešœ œ˜Jšœ$ œœ˜L——OšŸ ¢œ ¡œE¡œ ˜tOš Ÿ ¢œ+¡œ¡ œ-¡œÇ˜Ú—šœ ˜ šŸ1˜1J– "cedar" styleš˜J– "cedar" styleš˜J– "cedar" styleš˜J– "cedar" styleš˜—šŸ¢ Ÿ6˜CJ– "cedar" styleš œ¡ œ˜"J– "cedar" styleš œ¡ œ˜ J– "cedar" stylešœ¡ œ˜—šŸ¢Ÿ¢Ÿ œj¡ œ˜š– "cedar" stylešœ¡œ8˜RJ– "cedar" styleš¡œ¡œ˜—– "cedar" stylešœ¡œ-˜EJ– "cedar" styleš¡œ¡œ˜—J– "cedar" stylešœ¡œ;˜G—š¢ Ÿ.˜;– "cedar" stylešœ¡ œ˜J– "cedar" styleš¡œ¡œ˜—– "cedar" stylešœ¡ œ˜J– "cedar" styleš¡œ¡œ˜—– "cedar" stylešœ¡ œ˜J– "cedar" styleš¡œ¡œ˜$——šŸ¢ Ÿ/˜>J– "cedar" styleš˜J– "cedar" styleš ˜ J– "cedar" styleš˜———˜šŸ œI˜SJ– "cedar" styleš Ðakœ˜*J– "cedar" stylešœ ¡œ£ £œ˜)J– "cedar" stylešœ ¡œ¡œ ¡œ ˜0—šŸœ>˜LJ– "cedar" stylešœ˜%J– "cedar" styleš¡œ¡œœ¡œ¡œ ¡œ¡œ˜4—šŸœÁ˜ÔJ– "cedar" stylešœœÏc˜DJ– "cedar" stylešœ%£œ˜M—šŸœó˜ƒ– "cedar" stylešœ˜J– "cedar" styleš6œ˜9—– "cedar" stylešœ˜Jšœ¤1˜FJšœ¤˜+Jšœ¤˜3Jš£œ¤=˜JJš£œ¤<˜J—J– "cedar" stylešœ¡œ˜2J– "cedar" stylešœ ££ £˜5J– "cedar" styleš¡œ"œ˜:—šŸœ5˜R– "cedar" stylešœ˜– "cedar" styleš¡œ¡œ+¡œ˜EJ– "cedar" styleš¡œ ˜(——J– "cedar" stylešœ$œ˜?——šœ  œ œ˜˜Oš¢Ÿ¢Ÿœ"˜lOš Ÿ¢Ÿ¢Ÿ¢Ÿ¢œ¡œ ¡œ˜oOšŸ¢œ˜ OšŸœ2˜I—šŸ¢ Ÿ˜OšŸ¢Ÿ¢Ÿ˜OšŸ(¢œ˜FšŸ)œp¡œ¡œ˜«J– "cedar" styleš œ ¡œ ¡œ¡œÐaiÑaik¥¦¥6˜–——Nšœ¡œ˜OšŸMœÐ˜—˜šŸ+œ”˜¿J– "Cedar" stylešÐacW˜W—šŸHœ—˜ßproc– "Cedar" stylešœ¡˜ Jšœ ¡œ¡œ˜Jšœ ¡œ ¡œ˜3Jš¡œ¡œ¡œ˜Jš§K˜KJš§)˜)——šŸ¢ œ†˜—J– "cedar" styleš££˜ J– "cedar" styleš'˜'– "cedar" styleš'˜'J– "cedar" styleš§.˜.—– "cedar" styleš'˜'J– "cedar" styleš§˜—– "cedar" styleš'˜'J– "cedar" styleš§˜—– "cedar" styleš*˜*J– "cedar" styleš§¨˜¨———˜JšŸ˜—M˜ ˜ëJšžžŸœŸœœœŸ œ;œ)˜Œ—JšœX˜Xbanner– "cedar" styleš¤˜I modheader– "Cedar" styleš¤/˜/ – "Cedar" stylešœ ¡ ˜R– "Cedar" stylešœ¡˜Jšœ ¡œ¡œ˜Jšœ¡œ¤3˜?Jšœ¡œ˜PšÏn œ¡ œ¡œ ¤˜HPš¨œ¡ œ ˜Pš¨œ¡ œ ˜Pš¤Ðck¤˜Pš¤)˜)Pš ¨œ¡ œ¡œ¡œ¡œ˜BPš¤(˜(Jš¡œ˜—R˜ÑRš¡œ¡˜ šœ,¡˜.Jš¤Å˜Å— šœ)˜)Jš¤'˜'— šœ(˜(Jš¤(˜( šœ˜Jš¤˜——— – "cedar" styleš¤˜R– "cedar" styleš¤/˜/Rš¡ œ ¡œ6˜Q šœ¡˜Jš¡œ˜Ršœ¡˜Jšœ¡œ˜š¨ œ¡œ˜Jš¤[˜[Jšœ)˜)Jšœ0˜0Jšœ¡œ˜ Jšœ#¡œ¤"˜]Jš¡œ ¡œ¡œ¤˜HJš¡œ'¡œ˜3J˜—Jš¡œ¤˜—R˜ÏRš¡ ˜ ˜+Jš¤˜ šœ(˜(Jš¤=˜=—— šœ(˜(Jš¤©¤˜— ˜Jš¤˜—— – "Cedar" styleš¤˜R– "cedar" styleš¤/˜/ – "cedar" styleš¡ ˜ J– "cedar" stylešœ ˜ — – "cedar" stylešœ¡˜Jš¡œ ˜Jš¡œ ˜Ršœ¡œ¡œ ˜Jš¤˜Jšœ ¡œ¡œ¤$˜>šœ¡ œ¡˜Jšœ¡œ˜ Jšœ¡œ¡œ˜Jšœ¡œ˜ —š¨ œ¡œ¡œ ˜2Jš¡œ¡œ!˜,J˜—Jš¤˜š¨œ¡œ˜'Jšœ¤˜ J˜—š¨œ¡œ˜'Jš ¡œ ¡œ ¡œ¡œ¡œ¡œ¤˜]J˜—š ¨œ¡œ¡œ¡œ¡œ˜OJš¡œ¡œ˜.Jšœ˜J˜J˜—Jš¡œ¤˜—R˜ßRš¡œ¡˜ ˜-Jš¤˜— šœ(˜(Jš¤˜— šœ(˜(Jš¤-©¤˜9— ˜Jš¤˜—J˜—J˜—…—4ÒDU