OBJECT MODELS, CONSTRAINTS, AND PROLOG UML2-1 More than Class Diagrams • Often you need to show instances of models • use object diagrams or database tables • You need constraints, when class diagrams are insufficient and they almost always are • Object Constraint Language (OCL) is the proposed standard • I don’t like it – few do • I use Prolog instead – why? » it is a fundamental language in CS, not one that is hacked » it is declarative also like OCL » you can learn OCL when you need to – a small subset of Prolog is sufficient for our use UML2-2 when we want to see more… OBJECT MODELS UML2-3 Object Models • Object Models are are instances of class diagrams • Nodes are individual objects and links are relationships. Ex: e1 : Employee age : Integer = 33 d1 : Department minAge : Integer = 30 e2 : Employee Employee * 1 +age : Integer Department +minAge : Integer -employs -worksIn Class Diagram ED age : Integer = 35 e3 : Employee age : Integer = 54 e4 : Employee d2 : Department age : Integer = 24 minAge : Integer = 20 e5 : Employee age : Integer = 29 Object Model that conforms to class diagram ED • An Object Model shows instance, type, attribute information • There are LOTS of different kinds of object models you’ll see UML2-4 Class Diagram → Schema Mapping • Schema – set of table definitions • 1 table per UML class • 1 row per table for each object • 1 column per attribute • 1 extra column (#) for internal identifier this is where a wee bit of databases would help you • Each association is encoded by a 1 or 0..1 attribute • name is role name • no set valued attributes • For each class, the number of columns = 1 for object identifier + number of attributes listed + 1 for every 1 or 0..1 association end of the class Employee * 1 Department +minAge : Integer +age : Integer -employs -worksIn # of columns/table? UML2-5 Example Employee * 1 +age : Integer +minAge : Integer -employs Employee Employee# Department -worksIn Department age worksin Department# minAge of type Department# • Remember: each association turns into a single attribute of a 1 or 0..1 end • This works because each association is a 2-way inverse relationship. One attribute is sufficient. The “Remember” rule eliminates redundancy UML2-6 Object Models Encoded as Tables Department Table e1 : Employee age : Integer = 33 d1 : Department # minAge d1 30 minAge : Integer = 30 e2 : Employee age : Integer = 35 Employee Table e3 : Employee age : Integer = 54 # age worksIn e1 33 d1 e2 35 d1 e3 54 d1 UML2-7 Database Tables for those of you who are database savvy • Use normalized Relational Tables – they don’t have set-valued attributes • Null values are OK a null is a scalar! So instead of: Employee Objects Employee Table # age worksIn # age worksIn e1 33 d1 e1 33 d1 e2 35 d1 e2 35 d1 e3 54 d1 e3 54 d1 columns for both ends of an association Department Objects database tables Q: why does this xform lose no info? Department Table # minAge employs # minAge d1 30 {e1, e2, e3} d1 30 UML2-8 Here’s the Rule (Reason): or UML2-9 What Does This Require? • All associations must be of the form 1. . š or (0 − 1). . š, never ∗. .∗ • This is where the association class transformation rewrite is used • Recall this slide from the last lecture: Association Classes • Links can have an attached class called an Association Class • Gives association “attributes” and “methods” • Above diagram can be transformed to the equivalent diagram below • Hint: always use the bottom notation, never the top * Student * Course Enroll +student : Student +course : Course Student Course 1 1 Enroll * * UML1-34 UML2-10 Example #1 • Instead of: Student Student Course * … * Student# … 1 * Enroll# s1 {c1,c2} s2 {c2} … Enroll 1 * Student# Course# Course Enroll# c1 {s1} c2 {s1,s2} s1 equivalent s2 but always use right side as the answer Enroll# Student# Course# e1 s1 c1 e2 s1 c2 e3 s2 c2 Course# … c1 c2 UML2-11 Example #2 • Start with: ParentOrGuardian Child 2..* 1..* rewrite to • Rewrite to: PersonOrGuardian • Now create tables Child 1 1 Assoc 2..* 1..* UML2-12 Inheritance in Tables • Lots of ways: here is the simplest • Create a table for each non-abstract class • Objects that belong only to that class are listed as rows; infer objects rows that belong to subclasses, just as in Java crewman crewman -fname -lname commander commander -rank lieutenant -specialty lieutenant # fname lname c1 mr spock # fname lname rank c2 james kirk captain c3 christopher pike captain # fname lname specialty c4 hikaru sulu navigation c5 leonard mccoy physician UML2-13 ocl and prolog CONSTRAINTS UML2-14 Consider the Model Person -ownedByPerson -owns -name : String Kontract -owns -ownedByCompany -value : Integer 0..1 * Company -name : String * 0..1 • A kontract must be owned by a person or by a company BUT NOT BOTH • Further: the value of a kontract depends on the owner: • if Company has kontract: value > 500K • if Person has kontract: value < 100K • How can these constraints be expressed? UML2-15 Could Rewrite Original Diagram • To use an abstract class to solve only the ownerkontract problem • that’s not so good because the diagram is more complex • Still cannot express constraints on values without diagram distortion – for just a few constraints – imagine what would happen if there are lots of constraints! Kontract -value : Integer -owns * -ownedBy 1 KontractOwner Person Company • This isn’t the right way to go… UML2-16 Constraints! • When UML diagrams are insufficient they almost always are write constraints • Formal languages are hard for typical programmers to use and understand • So the Object Constraint Language (OCL) was invented to make constraints hard for everyone to write and understand ļ • note the intent of the designers, but… • Lessons from databases were not learned. OCL is very much tied to the navigability of the class structure. This forces you as a designer to write your OCL constraints in terms of navigability. Database people learned decades ago this was a bad idea • Tools are inconsistent although there are “standards” and may even be useable UML2-17 Forget OCL! Use Prolog! • OCL is an engineer-crafted functional language • declarative • documentation is awful • implementations are worse • language is to me a hack • Prolog solved a similar problem long ago • declarative • documentation is decent • implementations are very good • language is fundamental to Computer Science UML2-18 need a language to write constraints – use prolog! TUTORIAL ON PROLOG UML2-19 Prolog Atoms • Very popular in 1980s – has evolved to datalog in database area for dealing with large fact bases • Excellent for reasoning; awful at complex input-output or string manipulation • Atom – lowercase name, single-quoted text, or a number • also can be double-quoted text, which we won’t use batory ‘batory’ 45 3.52 Note: unquoted atom and quoted atom are different equal(batory, ‘batory’) is false! Note: unquoted names MUST begin with a lowercase letter!!!! UML2-20 Prolog Lists – Likely Won’t Need • Lists are one of the two basic data structures in Prolog [ a, b, c, d, e, f ] • Typically, you want to design your program with lists of atoms that are of the same type – lowercase names, single-quoted strings, or numbers: [ ‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’ ] [ 1, 2, 3, 4, 5, 6 ] • Prolog is an untyped language, so you can have lists of lists, lists of a mixture of atoms, etc. By programming discipline, you enforce lists of atoms of the same type • Very likely you will won’t use lists at all as this is where Prolog becomes complex UML2-21 Prolog Tuples • Other basic data structure in Prolog is tuple – this is how Prolog represents facts • Here is how we will represent tables in Prolog: a tuple defining the schema of the table, followed by the tuples of the table parent father child a0 a1 a1 a2 a2 a3 a2 a4 list table(parent,[father,child]). equivalent parent(a0,a1). parent(a1,a2). parent(a2,a3). parent(a2,a4). 1st line declares parent table always starts with a LOWER-CASE letter! with list of 2 attributes: father and child – both attributes are atomic names next 4 lines are rows of a table – all facts end in period (.) UML2-22 Prolog Queries • Uses pattern matching – unbound variables to be matched are UPPERCASE • Query: Who are the children of a2? ?- parent(a2,C). • Query: Who are the parents of a2? ?- parent(P,a2). UML2-23 Prolog Rules • Based on unification pattern matching – free or unbound variables are names starting with UPPER case to distinguish them from atomic values • Rules of the form HEAD :- BODY. See wikibooks click here % parent(X,Y) – X is a parent of Y % descendant(X,Y) - a descendant of X is Y % ancestor(X,Y) - an ancestor of X is Y “,” = and descendant(X,Y) :- parent(X,Y). descendant(X,Y) :- parent(X,Z),descendant(Z,Y). ancestor(X,Y) :- descendant(Y,X). UML2-24 Prolog Rule Execution • Match the initial definition first, if it fails, go to the next definition, until no definition exists, at which point, failure execution halt occurs % a descendant of X is Y; X is a parent of Y table(parent,[father,child]). descendant(X,Y) :- parent(X,Y). descendant(X,Y) :- parent(X,Z),descendant(Z,Y). parent(a0,a1). parent(a1,a2). parent(a2,a3). parent(a2,a4). ancestor(X,Y) :- descendant(Y,X). descendant(a2,Y) succeeds with Y=a3,a4. go onto next rule • Try this: descendant(a2,Y). a3 a0 a1 a2 descendant(a2,Y) succeeds with parent(a2,Z) Z=a3,a4 descendant(a3,Y) fails descendant(a4,Y) fails go onto next rule a4 no more rules – done! UML2-25 Prolog Rule Execution • I use SWI-Prolog – works on Windows and Mac OS X platforms, even Eclipse • Watch Video: UML2-26 BACK TO UML CONSTRAINTS UML2-27 Example Database in Prolog -ownedByPerson Person -owns -name : String Kontract -owns -ownedByCompany -value : Integer 0..1 p# name p1 Batory p2 Lin p3 Browne k# value c# k1 740 c1 k2 220 k3 330 k4 47 * p# p2 c1 Ace Plumbing c2 Rudys BBQ c4 Os Cafeteria * 0..1 table(company,[cid,"name"]). table(kontract,[kid,value,cid,pid]). table(person,[pid,"name"]). c2 name -name : String kontract.pl p1 c# Company equivalent person(p1,'Batory'). person(p2,'Lin'). person(p3,'Browne'). kontract(k1,740,c1,null). kontract(k2,220,null,p1). kontract(k3,330,c2,null). kontract(k4,47,null,p2). company(c1,'Ace Plumbing'). company(c2,'Rudys BBQ'). company(c4,'Os Cafeteria') UML2-28 Watch Video • Facts or rules always start with a lowercase letter: kontract, person, company • Unbound variables always start with an uppercase letter: Company, Person • Type <space> after each binding to get the next binding UML2-29 Prolog Constraints • A kontract must be owned by a person or by a company, NOT BOTH • If Company has kontract: value > 500K • If Person has kontract: value < 100K % kontract constraint – precisely 1 is nonnull one(C,P):- C==null, not(P==null). one(C,P):- not(C==null), P==null. kontractConstraint :forall(kontract(_,_,C,P),one(C,P)). % company constraint companyConstraint :forall(kontract(_,V,C,null),cc(V,C)). cc(V,C) :- V>500,company(C,_). % person constraint personConstraint :forall(kontract(_,V,null,P),pc(V,P)). pc(V,P) :- V<100,person(P,_). run:-companyConstraint, personConstraint, kontractConstraint. question: is there a better kontract constraint? UML2-30 Or A More Compact Way • A kontract must be owned by a person or by a company, NOT BOTH % all 3 constraints • If Company has kontract: value > 500K run:-all3Constraints. all3(V,C,P):-V>500,not(C==null),P==null,company(C,_). all3(V,C,P):-V<100,not(P==null),C==null,person(P,_). all3Constraints:forall(kontract(_,V,C,P),all3(V,C,P)). • If Person has kontract: value < 100K UML2-31 Watch Video • Prolog hints: • When you build your constraints, always test them individually k# value c# k1 740 c1 k2 220 k3 330 k4 47 p# p1 c2 p2 UML2-32 constraint violations tell us nothing ERROR MESSAGES SUCK SOMETHING AWFUL… UML2-33 Want Better Error Messages • Identify rows of tables that are offensive • Simple fix – add extra rules isError(S,N) :- tell(user_error),write(S),writeln(N),told. % kontract database constraints % kontract constraint notBoth(_,C,P) :- C==null,not(P==null),person(P,_). notBoth(_,C,P) :- not(C==null),P==null,company(C,_). notBoth(K,_,_) :- isError('kontract fails constraint ',K). kontractConstraint :- forall(kontract(K,_,C,P),notBoth(K,C,P)). % company constraint companyConstraint :- forall(kontract(K,V,C,null),cc(K,V,C)). cc(_,V,C) :- company(C,_),V>500. cc(K,_,_) :- isError('company fails kontract constraint ',K). % person constraint % virtually same as company constraint run :- kontractConstraint, companyConstraint, personConstraint. UML2-34 Beware! • Try to write your constraints in the form: foreach( findAnError(X), isError(‘violation ’,X)). • where findAnError(X) defines a predicate that binds to an error X • Do NOT write constraints as: foreach( tuple(X), checkError(X) ). checkError(X) :- ErrorCondition(X), IsError(‘violation ‘,X)). • Why?: if checkError fails just once, foreach stops and fails. Make sure you understand this! UML2-35 Watch Video • Better error reporting UML2-36 PERSPECTIVES UML2-37 OCL as of today is Likely Insufficient • Suppose we define a UML model whose instances are rings of 3Īk nodes (kļ³1) 1 Node -next 1 conforms ļ conforms • I have no idea on how to write this constraint and many others in OCL • may need to add more “basic” operations to OCL • OCL cannot update values – it is a read-only language • need a Turing-complete language like Prolog, perhaps? • Solving this problem took me hours because I didn’t know prolog very well The solution is simple – but you have to work hard at it to make it so UML2-38 Even Simpler Example richEmployee -Salary : Integer reConstraint:-forall(richEmployee(_,S),S>500). • A richEmployee has a salary in excess of 500K • Can not check this constraint statically • Must check it at run-time, but when…? – at epochs – points in time when consistency must be guaranteed – in MDE, you create an instance of a model by drag and drop like Visio You then push a “validate” button that tells you if the instance satisfies constraints UML2-39 Recap • Almost all class diagrams need constraints • to eliminate incorrect or unwanted instances • Standard today is to use Object Constraint Language (OCL) • I prefer Prolog • Why? • represent object models as database tables • Prolog was designed with tables in mind • Prolog can also be used to map databases to other databases which we won’t cover in this class UML2-40