CedarProgramStyle.tioga
Created by Jim Mitchell long ago ...
Last Edited by Mitchell on December 20, 1982 5:28 pm
Last Edited by Beach, May 9, 1984 5:01:14 pm PDT
Polle Zellweger (PTZ) June 28, 1988 12:17:32 pm PDT
Last Edited by: Subhana, May 30, 1984 12:06:56 pm PDT
Last changed by Pavel on May 5, 1989 5:01:50 pm PDT
Willie-Sue, December 29, 1987 3:38:51 pm PST
Christian Jacobi, May 19, 1992 2:09 pm PDT
STYLIZING CEDAR PROGRAMS
STYLIZING CEDAR PROGRAMS
CEDAR 10.1 —
CEDAR 10.1 —
Stylizing Cedar Programs
Stored as [Cedar10.1]<CedarDoc>CedarProgramStyle.tioga
© Copyright 1984, 1987, 1988, 1989, 1992 Xerox Corporation. All rights reserved.
Abstract: styl"ize tr.v. -ized, -izing, -izes.
1. To subordinate verisimilitude to principles of design in the representation of.
2. To represent conventionally; conventionalize.
[If you are reading this document on-line, try using the Tioga Levels menu to initially browse the top few levels of its structure before reading it straight through.]
XEROX Xerox Corporation
Palo Alto Research Center
3333 Coyote Hill Road
Palo Alto, California 94304
Contents
0. Introduction
1. Names
1.1. Capitalization
1.2. Qualification
1.3. Module Naming
2. Types
3. Exceptions
: SIGNALs and
ERRORs
3.1. General
3.2. In DEFINITIONS modules
3.3. In PROGRAM modules
4. Programming constructs
5. Module comments
6. Program layout
7. The Fuglemen
7.1. Fugleman.mesa
7.2. FuglemanClient.mesa
7.3. FuglemanImpl.mesa
0. Introduction
styl
"
ize
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 certainly does have value.
The conventions presented here have been generally agreed upon by the Cedar programming community and are approximations to current practice. Consequently, they cannot be 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 usually 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 rules are highlighted like this while the parts that illustrate the rule are highlighted like this.
1. Names
1.1. Capitalization
Capitalize the first letter of a name
if it identifies a module (interface or implementation), procedure, signal, or type, otherwise the first letter is lower-case:
Fugleman: CEDAR 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 are some exceptions: if one has a type,
Foo, it is okay to declare a variable of that type as
foo; it is acceptable to name a condition variable and a
BOOLEAN describing the condition similarly:
badID, badId, bADid, BADid: INT -- BAD!
complex: Complex; -- acceptable
c: Complex; -- acceptable
1.2. Qualification
Identifiers from interfaces should be qualified
by their interface names or abbreviations for them:
DIRECTORY
Commander, IO, Process, Rope;
SimpleExample:
CEDAR MONITOR
IMPORTS Commander, IO, Process, Rope =
. . .
ReverseName: Commander.CommandProc = BEGIN . . . END;
execStream: IO.Handle;
Renaming an interface in the
IMPORTS clause
is okay, provided that you don't use both names in the program.
SimpleExample:
CEDAR MONITOR
IMPORTS Process, Rope, X: Commander =
. . .
ReverseName: X.CommandProc = ...
The qualified/renaming form of
OPEN should be used
instead of the unqualified form.
OPEN G: Graphics;
There are few valid reasons for using an unqualified OPEN
It is acceptable over the scope of an entire PROGRAM module only for the DEFINITIONS module that the module 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.
1.3. Module Naming
All module source 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: CEDAR DEFINITIONS = . . .
ListSortRef: CEDAR DEFINITIONS = . . .
Rope: CEDAR DEFINITIONS = . . .
A
PROGRAM or
MONITOR module name should have the suffix ``Impl''
if its name without the suffix would conflict with the name of a
DEFINITIONS module.
ObjectSupportImpl:
CEDAR
PROGRAM
-- name would conflict with ObjectSupport without Impl
EXPORTS ObjectSupport = . . .
ObjectMachinery:
CEDAR
PROGRAM
-- name doesn't conflict with ObjectSupport
EXPORTS ObjectSupport = . . .
Fun: CEDAR PROGRAM = -- name conflicts with nothing
A
CONFIGURATION module does not need any standard suffix on its name, However, the suffix Package is also used frequently.
Rigging:
CONFIGURATION
EXPORTS Rope = . . .
Compiler:
CONFIGURATION
EXPORTS ExecOps, CompilerOps = . . .
TIPPackage:
CONFIGURATION
. . . = . . .
XTkPackage:
CONFIGURATION
. . . = . . .
A
CONFIGURATION file name should have the extension ``.config''.
Rigging.config
Compiler.config
TIPPackage.config
XTkPackage.config
2. 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
Use closed lower bounds and open upper bounds
for interval types:
[0..upperLimit) -- preferred form
FOR i IN [0..n) DO IF a[i]=a[n] THEN . . . ENDLOOP;
Use positional notation for single-component argument lists,
record constructors, and extractors. Positional notation is also acceptable if there are multiple components, all of different types:
ViewerTools.SetSelection[handle.fact.input]; -- force the selection
IO.PutF[execStream, "Your user name backwards is: %g\n", IO.rope[backwordsName]];
Use the keyword form
for argument lists, record constructors, and extractors 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:
Imager.DrawBox[
context, 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]];
Name procedure parameters
in the definitions of procedure types in
DEFINITIONS modules:
CommandProc: TYPE = PROC [exec: ExecHandle, clientData: REF ANY ← NIL] RETURNS[ok: BOOLEAN ← TRUE];
Name procedure result fields,
especially if there is more than one:
CreateBarGraph:
PROC [x, y, w, h:
INT, parent: ViewerClasses.Viewer, fullScale:
REAL]
RETURNS [barGraph: ViewerClasses.Viewer]
FindItem: PROC[k: Key] RETURNS [v: Value, found: BOOLEAN];
3. Exceptions
: SIGNALs and
ERRORs
3.1. General
Use
ENDCASE only to generate an
ERROR or to treat "none of the above",
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.
except for "impossible" conditions.
Locally defined signals shouldn't escape from an abstraction
and need not conform to the conventions below.
3.2. In
DEFINITIONS modules
Declare
ERRORs as
ERRORs and
SIGNALs as
SIGNALs.
Don't declare a
SIGNAL and then generate an
ERROR with it.
Try to define a small number of ERRORs and SIGNALs in an interface.
Normally define a single ERROR/SIGNAL with a parameter to distinguish the exact reason for it. Only use separate names for separate signals when they must have different types for reasons of resumption:
IOError: ERROR [ec: ErrorCode];
ErrorCode: TYPE = {NotImplementedForThisStream, IllegalPutBack, SyntaxError, StreamClosed, FileNotFound, FileAlreadyExists, IllegalFileName, WrongTransactionType, FileTooLong, BadIndex};
IOSignal: SIGNAL [ec: SignalCode];
SignalCode: TYPE = {EmptyBuffer, UnmatchedLeftParen, UnmatchedStringDelim, Rubout, UnprintableValue, TypeMismatch, UnknownFormat};
BufferOverFlow: SIGNAL[text: REF TEXT] RETURNS[REF TEXT];
-- used by text streams, should return a bigger one, with characters copied over, or else can return same text with length reset after having done something with chartacters.
Indicate which
SIGNALs or
ERRORs are generated by a procedure
in the comments of an interface 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
GetRefAny: PROC [stream: STREAM] RETURNS [REF ANY]; -- from IO
-- SIGNALs: IOSignal[UnmatchedLeftParen, UnmatchedStringDelim]; resumption causes GetRefAny to supply the missing right parenthesis or quote.
3.3. 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: handle them completely within your abstraction, or transform them into exceptions that are part of your interface (i.e., insulate your clients from details of your implementation).
... inputNumber ← Convert.IntFromRope[contents -- from SampleTool
! SafeStorage.NarrowFault => {inputNumber←-1; CONTINUE}];
4. Programming constructs
Ensure that the target type for a
NARROW is obvious
either by naming it explicitly or using it in a simple context.
handle: Handle ← NARROW[clientData]; -- target type = Handle
a: INT = IO.GetInt[IO.RIS[NARROW[first, ROPE]]]; -- target type = ROPE
Use
TRUSTED over the most confining region in which it is needed.
TRUSTED {Process.Detach[FORK EvalLoop[ ]]};
5. Module comments
The first few lines of a source module
should be comments, the first giving the file name for the module, and the following giving the names of the people who last edited it and when they did so. The EditorComforts software package will, if you've installed it, update the last-edited date automatically when you save the file. See EditorComfortsDoc.tioga for details.
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 Interpreter.
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.
6. Program layout
Use Cedar.abbreviations
See the description of the "Expand Abbreviation" command in the Tioga manual, TiogaDoc.tioga. It has the dual benefits of making it easier to enter code and making that code look more alike across multiple programmers.
Use Tioga Mesa formatting
for Mesa keywords, comments, and procedure names. See the description of the "Automatic Mesa formatting" feature in the Tioga manual.
7. The Fuglemen
This section consists of a set of skeletal programs, Fugleman, FuglemanImpl, and FuglemanClient, that use the conventions expounded in the above style discussion. The name Fugleman comes from the following definition:
fu"gle"man 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.
7.1. Fugleman.mesa
This is a template for defining the interface for a class, Fugleman, of objects. 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.
Fugleman.mesa
Last Edited by Pavel, May 5, 1989 4:56:37 pm PDT
Fugleman: CEDAR DEFINITIONS =
BEGIN
Handle: TYPE = REF Rep;
Rep: TYPE; -- opaque type for the representation of the object
FugleFailure: ERROR;
NewFugleman:
PROC
[] RETURNS [Handle];
Makes a new Fugleman object
Print: PROC [h: Handle];
Check:
PROC [h: Handle];
ERRORs: FugleFailure
Returns normally if Fugleman object OK
SomeProc:
PROC [h: Handle, otherArgument:
INT]
RETURNS [
INT];
Comment goes here saying what it does
END.
7.2. FuglemanClient.mesa
This is an example intended only to show syntactically how client programs create values, invoke operations on them and catch signals that those operations might generate. The files Fugleman.mesa and FuglemanImpl.mesa contain the definition of the interface used here and a sample implementation of it, respectively.
FuglemanClient.mesa
Last Edited by Pavel, May 5, 1989 4:56:27 pm PDT
DIRECTORY
Fugleman USING [Handle, NewFugleman, Check, SomeProc, FugleFailure];
FuglemanClient:
CEDAR PROGRAM
IMPORTS Fugles: Fugleman =
BEGIN
TestError: ERROR;
SimpleTest:
PROC =
BEGIN
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;
Fugles.Check[fm ! Fugles.FugleFailure => ERROR TestError]; -- check the object, convert error
IF fm=anotherFm
THEN
ERROR TestError; -- should get unique objects
IF Fugles.SomeProc[fm, 1] = Fugles.SomeProc[anotherFm, 2]
THEN
x ← 2;
END;
SimpleTest[]; -- call the test procedure
END. -- FuglemanClient
7.3. FuglemanImpl.mesa
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.
FuglemanImpl.mesa
Last Edited by Pavel, May 5, 1989 4:56:11 pm PDT
FuglemanImpl:
CEDAR PROGRAM
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
];
FugleFailure: PUBLIC ERROR = CODE;
NewFugleman:
PUBLIC PROC
[] RETURNS [Handle] =
BEGIN
RETURN [NEW[Rep ← [count: 5, mumble: -10]]];
END;
Operations on a Fugleman
Print:
PUBLIC PROC [h: Handle] =
BEGIN
some code would go here
END;
Check:
PUBLIC PROC [h: Handle] =
BEGIN
IF h.count>100
OR h.mumble<0
AND
NOT h.flag
THEN
ERROR FugleFailure; -- it's only an example
END;
SomeProc:
PUBLIC PROC [h: Handle, otherArgument:
INT]
RETURNS [
r: INT] =
BEGIN
IF otherArgument>100
THEN
otherArgument ← 100;
h.count ← otherArgument;
r ← 17;
END;
END. -- FuglemanImpl