CSC 509 Lecture Notes Week 2
High-Level Inferno Design;
Rolodex MVP Design Example
The "Big Picture" -- Some High-Level Inferno Design
Figure 1: Inferno subsystem diagram.
Figure 2: Inferno subsystem diagram.
The "Smaller Picture" -- Rolodex MVP Design Example
~gfisher/projects/alpha/support/design/view.java ~gfisher/projects/alpha/support/design/model.java
contains all the example files discussed in these notes.~gfisher/projects/alpha/rolodex
~gfisher/projects/alpha/rolodex/implementation/java/Makefile
(This Java API document was generated using javadoc, which we will use to generate our .html files stored in the project design directories.)http://www.java.sun.com/products/jdk/1.2/docs/api/index.html
Figure 3: Top-Level Rolodex Interface.
Figure 4: Dialog for Adding a Rolodex Card.
Figure 5: Dialogs for Finding, Changing, or Deleting a Card.
1 (**** 2 * 3 * Module Rolodex defines the main Rolodex object, its component objects, and 4 * the rolodex editing operations. 5 * 6 *) 7 8 module Rolodex; 9 10 export Rolodex, Card, Name; 11 12 object Rolodex is 13 components: Card*; 14 description: (* 15 A Roldex is a collection of cards. 16 *); 17 end Rolodex; 18 19 object Card is 20 components: n:Name and id:Id and age:Age and s:Sex and addr:Address; 21 description: (* 22 A Card contains the information for a person stored in a Rolodex: name, 23 id, age, sex, and street address. 24 *); 25 end Card; 26 27 object Name is string; 28 object Id is integer; 29 object Age is integer; 30 object Sex is Male or Female; 31 object Male; 32 object Female; 33 object Address is string; 34 35 operation Add 36 inputs: r:Rolodex, c:Card; 37 outputs: r':Rolodex; 38 39 description: (* 40 Add the given card to the given rolodex if a card of the same id is not 41 already there. 42 *); 43 44 precondition: 45 (* 46 * There is no card in the input Rolodex with the same id as the given 47 * input card. 48 *) 49 not CardAlreadyThere(c, r) 50 51 and 52 53 (* 54 * The values of the given card fields are valid. 55 *) 56 CardIsValid(c); 57 58 postcondition: 59 (* 60 * A card is in the output rolodex iff it is in the input rolodex or 61 * it's the new card to be added. 62 *) 63 forall (c':Card) 64 (c' in r') iff ((c' in r) or (c' = c)); 65 66 end Add; 67 68 operation Delete 69 inputs: r:Rolodex, id:Id; 70 outputs: r':Rolodex; 71 72 description: (* 73 Delete the card of the given id from the given rolodex. 74 *); 75 76 precondition: 77 (* 78 * There is a card of the given id in the input Rolodex. 79 *) 80 exists (c' in r) c'.id = id; 81 82 postcondition: 83 (* 84 * A card is in the output rolodex iff it is in the input rolodex and 85 * its id is different than the given id. 86 *) 87 forall (c':Card) 88 (c' in r') iff ((c' in r) and (c'.id != id)); 89 90 end Delete; 91 92 operation Change 93 inputs: r:Rolodex, id:Id, c:Card; 94 outputs: r':Rolodex; 95 description: (* 96 Change the card of the given id in the given rolodex to the given new 97 card. 98 *); 99 100 precondition: 101 (* 102 * There is a card of the given id in the input Rolodex, and that card 103 * is not identical with the given input card, and the given card is 104 * valid (as for Add). 105 *) 106 exists (c' in r) (c'.id = id) and (c' != c) and CardIsValid(c); 107 108 109 postcondition: 110 (* 111 * A card is in the output rolodex iff it is in the input rolodex and 112 * is not the card with the given id in the input rolodex, or it's the 113 * given input card. 114 *) 115 forall (c':Card) 116 (c' in r') iff (((c' in r) and 117 (not exists (c'' in r) (c''.id = id) and (c'' = c'))) or 118 (c' = c)); 119 120 end Change; 121 122 operation Find 123 inputs: r:Rolodex, n:Name; 124 outputs: cl:Card*; 125 description: (* 126 Find all of the cards of the given name in the given rolodex. 127 *); 128 postcondition: 129 130 (* 131 * Cards in the output list consist of those in the input Rolodex with 132 * the given name. 133 *) 134 forall (c:Card) 135 (c in cl) iff ((c in r) and (c.n = n)) 136 137 and 138 139 (* 140 * If the the output card list has more than one card, it is sorted in 141 * ascending order by card id. 142 *) 143 if (#cl > 1) then 144 forall (i:integer | (i >= 1) and (i < #cl)) 145 cl[i].id < cl[i+1].id; 146 147 end Find; 148 149 function CardAlreadyThere(c:Card, r:Rolodex)->boolean = 150 not (exists (c' in r) c'.id = c.id); 151 152 function CardIsValid(c: Card)->boolean = 153 154 (* 155 * The length of the name is <= 30 characters. 156 *) 157 (#(c.n) <= 30) 158 159 and 160 161 (* 162 * The length (i.e, numer of digits) of the id is 9. 163 *) 164 (#(c.id) = 9) 165 166 and 167 168 (* 169 * The age is a reasonable range. 170 *) 171 ((c.age >= 0) and (c.age <= 200)) 172 173 and 174 175 (* 176 * The length of the address is <= 40 chars. 177 *) 178 (#(c.addr) < 40); 179 180 end Rolodex; 181
1 /** 2 * 3 * Class Rolodex is the model class for the basic rolodex object, including the 4 * edit operations to add, delete, change, and find rolodex entries. 5 * 6 */ 7 8 public class Rolodex implements Model { 9 10 /*-* 11 * Public Functions 12 */ 13 14 /** 15 * Construct an initially empty rolodex. Initialize the error objects for 16 * each function that throws an exception. 17 * <pre> 18 * post: (exists (CardList cl) (this'.cl == cl) and (cl.Len() == 0)) 19 * and 20 * (exists (AddInputErrors aie) (this'.aie == aie)); 21 * and 22 * (exists (DeleteInputError die) (this'.die == die)); 23 * and 24 * (exists (ChangeInputErrors cie) (this'.cie == cie)); 25 * </pre> 26 */ 27 public Rolodex(View v) {} 28 29 /** 30 * Add the given card to this if a card of the same id is not already there 31 * and there is room for another card. 32 * <pre> 33 * pre: 34 * // There is no card in the input this with the same id as the given 35 * // input card. 36 * not CardAlreadyThere(c) 37 * 38 * and 39 * 40 * // The values of the given card fields are valid. 41 * CardIsValid(c) 42 * 43 * and 44 * 45 * // There is room for another card. 46 * (cl.Len() < MAXCARDS) 47 * 48 * post: 49 * // If none of the preconditions is violated, then a normal 50 * // postcondition holds, else an exception is thrown. 51 * if (not AddPrecondsViolated(c)) ( 52 * // A card is in the output this iff it is in the input this or 53 * // it's the new card to be added. 54 * forall (Card c') this'.In(c') iff (In(c') or (c' == c)) 55 * 56 * and 57 * 58 * // The size of this is increased by 1. 59 * (cl'.Length() == cl.Length() + 1) 60 * ) 61 * else ( 62 * // An AddInputException is thrown if any of the preconditions 63 * // is violated. The value of the exception flag is set for 64 * // each violated precondition via the ValidataAddInput 65 * // function. 66 * (throw == aie) and (aie == ValidateAddInput(c)); 67 * </pre> 68 */ 69 public void add(Card c) {} 70 71 /** 72 * Delete the card of the given id from this. 73 * <pre> 74 * pre: 75 * // There is a card of the given id in the input this. 76 * exists (Card c' | In(c')) c'.getId() == id; 77 * 78 * post: 79 * // If the precondition is not violated, then a normal postcondition 80 * // holds, else an exception is thrown. 81 * if (DeletePrecondViolated(c)) then ( 82 * // A card is in the output this iff it is in the input this and 83 * // its id is different than the given id. 84 * forall (Card c') 85 * this'.In(c') iff (In(c') and (c'.id != id)); 86 * ) 87 * else 88 * // A DeleteInputException is thrown if the precondition is 89 * // violated. 90 * throw == die; 91 * </pre> 92 */ 93 public void delete(Id id) {} 94 95 /** 96 * Change the card of the given id in this to the given new card. 97 * 98 * <pre> 99 * pre: 100 * // There is a card of the given id in the input this and that card 101 * // is not identical with the given input card, and the given card 102 * // is valid. 103 * exists (Card c' | In(c') (c'.getId() == id) and 104 * (c' != c) and CardIsValid(c); 105 * 106 * post: 107 * // If the precondition is not violated, then a normal postcondition 108 * // holds, else an exception is thrown. 109 * if (ChangePrecondViolated(c)) then ( 110 * // A card is in the output this iff it is in the input this and 111 * // is not the card with the given id in the input this, or it's 112 * // the given input card. 113 * forall (Card c') 114 * this'.In(c') iff (In(c') and 115 * (not exists (Card c'' | In(c'')) 116 * (c''.getId() == id) and (c'' == c')) or 117 * (c' == c)) 118 * ) 119 * else 120 * // A ChangeInputException is thrown if the precondition is 121 * // violated. 122 * throw == cie; 123 * </pre> 124 */ 125 public void change(Id id, Card c) {} 126 127 /** 128 * Find all of the cards of the given name in this. 129 * <pre> 130 * post: 131 * // Cards in the output list consist of those in the input this with 132 * // the given name. 133 * forall (Card c) 134 * (cl.In(c) iff (In(c) and (c.getName() == n)) 135 * 136 * and 137 * 138 * // The output card list is sorted by ascending order of card id. 139 * forall (int i, int j | 140 * (i >= 1) and (i <= cl.Length()) and 141 * (j >= 1) and (j <= cl.Length())) 142 * if i < j then 143 * cl.get(i).getId() < cl.get(j).getId(); 144 * </pre> 145 */ 146 public CardList find(Name n) {} 147 148 /** 149 * Print this to stdout. In the current design, the specs are the same as 150 * Dump below, q.v. In general, if there is a distinction between Print 151 * and Dump it is that the former produces a more nicely formated output 152 * than the latter. 153 */ 154 public void print() {} 155 156 /** 157 * Dump this to stdout by dumping each card, in List.iterator order. 158 */ 159 public void dump() {} 160 161 162 /** 163 * View Service functions. These are functions that provide data 164 * manipulation services to the views that the views cannot know how to 165 * implement. 166 */ 167 168 /** 169 * Convert to the given string to one of the Sex enumeration literals. The 170 * String value must be all lower case and only the first character is 171 * significant, i.e., "m*" or "f*". If s is not one of these values, 172 * Female is returned. 173 * <pre> 174 * post: if (s[1] == "m") then return == Male else return == Female 175 * </pre> 176 */ 177 public Sex stringToSex(String s) {} 178 179 /** 180 * Convert to the given Sex enumeration literal to an lowercase string. 181 * <pre> 182 * post: if (s == Mail) then return == "m" else return == "f" 183 * </pre> 184 */ 185 String sexToString(Sex s) {} 186 187 188 /*-* 189 * Protected Functions 190 */ 191 192 /** 193 * Validate the given card per the precondition of Add. Return the 194 * appropriately set AddInputErrors value. See the definition of 195 * AddInputErrors for further information. 196 */ 197 protected AddInputErrors validateAddInput(Card c) {} 198 199 200 /*-* 201 * Data Members 202 */ 203 204 /** Simple list rep'n of the card list */ 205 protected CardList cl; 206 207 /** Error messages for the Add function */ 208 protected AddInputErrors aie; 209 210 /** Error message for the Delerte function */ 211 protected DeleteInputError die; 212 213 /** Error messages for the Change function */ 214 protected ChangeInputErrors cie; 215 216 217 /** 218 * Auxiliary spec functions. 219 * 220 * boolean cardAlreadyThere(Card c) { 221 * not (exists (Card c' | In(c')) 222 * c'.getId() == c.getId()) 223 * } 224 * 225 * boolean cardIsValid(Card c) { 226 * // The length of the name is <= 30 characters 227 * (c.getName().Length() <= 30); 228 * 229 * and 230 * 231 * // The length (i.e, numer of digits) of the id is 9 232 * c.getId().toString.Length() == 9) 233 * 234 * and 235 * 236 * // Age is a reasonable range 237 * ((c.getAge() >= 0) and (c.getAge() <= 200)) 238 * 239 * and 240 * 241 * // Sex is valid 242 * (c.getSex() != InvalidSex) 243 * 244 * and 245 * 246 * // The length of the address is <= 40 chars 247 * (c.getAddr() < 40) 248 * 249 * } 250 * 251 * boolean addPrecondsViolated(Card c) { 252 * cardAlreadyThere(c) or (not cardIsValid(c)); 253 * } 254 * 255 * boolean deletePrecondViolated(Card c) { 256 * not (exists (Card c' | In(c')) c'.getId() == id) 257 * } 258 * 259 * boolean changePrecondViolated(Card c) { 260 * not (exists (Card c' | In(c')) (c'.getId() == id) and 261 * (c' != c)); 262 * } 263 * 264 * boolean in(Card c); 265 * // Return true if the given card is anywhere in this. 266 * Find(c) != null 267 * 268 */ 269 270 };
1 /** 2 * 3 * Class Card is the model class for the Card object. A Card contains the 4 * basic information for a person stored in a Rolodex: name, SSN id, age, sex, 5 * and street address. 6 * 7 */ 8 9 public class Card implements Model { 10 11 /*-* 12 * Public Functions 13 */ 14 15 /** 16 * Construct a card with the given field values. Note that no validity 17 * checking of the given values is performed here. Rather, input value 18 * checking is done in the Rolodex::Add function, q.v. 19 * 20 * post: (this.n == n) and (this.id == id) and (this.age == age) and 21 * (this.s == s) and (this.addr == addr); 22 */ 23 public Card(Name n, Id id, Age age, Sex s, Address addr) {} 24 25 26 /*-* 27 * Field access functions. 28 */ 29 30 /** 31 * Return the name of this. 32 * <pre> 33 * post: return == n; 34 * </pre> 35 */ 36 public Name getName() {} 37 38 /** 39 * Return the id of this. 40 * <pre> 41 * post: return == id; 42 * </pre> 43 */ 44 public Id getId() {} 45 46 /** 47 * Return the age of this. 48 * 49 * post: return == age; 50 */ 51 public Age getAge() {} 52 53 /** 54 * Return the sex of this. 55 * 56 * post: return == s; 57 */ 58 public Sex getSex() {} 59 60 /** 61 * Return the name of this. 62 * 63 * post: return == addr; 64 */ 65 public Address getAddr() {} 66 67 /* 68 * Return true if this is deep equal to the given card , i.e. card all of 69 * the fields of this are equal to all of the fields of the given card. 70 * 71 * post: (this.n == c.n) and (this.id == c.id) and 72 * (this.age == c.age) and (this.s == c.s) and 73 * (this.addr == c.addr); 74 */ 75 public Boolean equal(Card c) {} 76 77 /* 78 * Print this to stdout. In the current design, the specs are the same as 79 * Dump below, q.v. In general, if there is a distinction between Print 80 * and Dump it is that the former produces a more nicely formated output 81 * than the latter. 82 */ 83 public void print() {} 84 85 /** 86 * Dump this to stdout. 87 * 88 * post: (stdout == "Name: " + n + "0 + 89 * "Id: " + id + "0 + 90 * "Age: " + age + "0 + 91 * "Sex: " + s + "0 + 92 * "Addr: " + addr + "0) 93 */ 94 public void dump() {} 95 96 97 /*-* 98 * Data Members 99 */ 100 101 /** Person name and record search key */ 102 protected Name n; 103 104 /** Person id and unique record key */ 105 protected Id id; 106 107 /** Person age */ 108 protected Age age; 109 110 /** Person sex */ 111 protected Sex s; 112 113 /** Person street address */ 114 protected Address addr; 115 116 }
1 /** 2 * 3 * Class Name is the heavyweight translation of the RSL atomic object 4 * definition 5 * 6 * object Name is string; 7 * 8 * A lighter-weight class definition would have just a single public string 9 * data member. A wimped-out translation is to eliminate the mnemonic 10 * identifier "Name" entirely from the design, replacing it directly with type 11 * String. 12 * 13 */ 14 15 public class Name { 16 public Name(String value) {this.value = new String(value);} 17 public String getValue() {return value;} 18 protected String value; 19 }
is semantically equivalent to the following standard Java expressionif X then Y else Z
X ? Y : Z
is semantically equivalent to no standard Java expression, since Java always requires the "else" part of and if-then-else expression.if X then Y
for all types for which null is a legitimate value.X ? Y : null
name := expression
is semantically equivalent to the following standard C/C++ macro definition:X := Y
where X must be a syntactically legal Java identifier and Y must be a syntactically and semantically legal expression within the scope where the binding appears.#define X Y
The universal quantification form is read "for all variables declared in the simple-declarator-list such that expression1 is true, expression2 is true", and the "such that expression1 clause is optional. The existential form is read similarly.forall ( simple-declarator-list [ | expression1 ] ) expression2exists ( simple-declarator-list [ | expression1 ] ) expression2
where multiple bindings are separated by semicolons.MethodDeclaration: MethodHeader PrePostConditionsopt MethodBodyPrePostConditions: Bindingsopt Preconditionopt Postcondition
For example
int F(int x, int y); pre: (x <= 0) && (y >= 100); post: return == x+y; int G(Integer i, Integer j); let: x := i + j; y := i - j; z := x * y; w := i' + j'; pre: x < y; post: (x < y) && (return == z + w); int H(Integer i, Integer j, int k) { i = i+j; return i * k; }; post: (i' == i+j) && (j' == j) && (return == i' * k);
Figure 6: Top-level rolodex data design.
Figure 7: Top-level rolodex function design.