/* Daniel Barreto N. #04-36723 ---------------------------------------------------------------------- This assignment illustrates how specifications (esp invariants and preconditions) written in a formal language can help in removing errors in code. The assignment concerns a class "Taxpayer" that is used for taxpayers. */ class Taxpayer { /* FIELDS */ /* isFemale is true iff the person is female */ boolean isFemale; /* isMale is true iff the person is male */ boolean isMale; Taxpayer father, mother; // These fields won't really be used until // the next part of the exercise. /* Age in years */ int age; boolean isMarried; /* Reference to spouce if person is married, null otherwise */ Taxpayer spouse; /* Constant default income tax allowance (belastingvrije som) */ static final int DEFAULT_ALLOWANCE = 5000; /* Constant income tax allowance for Old Age Pensioners over 65 */ static final int ALLOWANCE_OAP = 7000; /* Income tax allowance (belastingvrije som) */ int tax_allowance; /* Income per year */ int income; /* CONSTRUCTOR */ //@ invariant isFemale != isMale; //@ invariant isMarried ==> (spouse != null); Taxpayer(boolean jongetje, Taxpayer ma, Taxpayer pa) { age = 0; isMarried = false; this.isMale = jongetje; this.isFemale = !jongetje; mother = ma; father = pa; spouse = null; income = 0; tax_allowance = DEFAULT_ALLOWANCE; /* The line below makes explicit the assumption that a new Taxpayer is not * married to anyone yet. A bit silly of course, but we need this to keep * ESC/Java2 happy. */ //@ assume (\forall Taxpayer p; p.spouse != this); } /* METHODS */ /* Marry to new_spouse */ //@ requires new_spouse != null; //@ requires (new_spouse.isFemale && this.isMale) || (new_spouse.isMale && this.isFemale); //@ ensures spouse != null; //@ ensures new_spouse.spouse == this; void marry(Taxpayer new_spouse) { new_spouse.spouse = this; spouse = new_spouse; isMarried = true; } /* Divorce from current spouse */ //@ requires spouse != null; //@ requires spouse.spouse == this; //@ requires spouse != this; //@ ensures spouse == null && isMarried == false; //@ ensures \old(spouse).spouse == null && \old(spouse).isMarried == false; //@ ensures age < 65 && \old(tax_allowance) > DEFAULT_ALLOWANCE ==> tax_allowance == DEFAULT_ALLOWANCE && \old(spouse).tax_allowance == \old(spouse.tax_allowance) + (\old(tax_allowance) - DEFAULT_ALLOWANCE); //@ ensures age >= 65 && \old(tax_allowance) > ALLOWANCE_OAP ==> tax_allowance == ALLOWANCE_OAP && \old(spouse).tax_allowance == \old(spouse.tax_allowance) + (\old(tax_allowance) - ALLOWANCE_OAP); void divorce() { if (age < 65 && tax_allowance > DEFAULT_ALLOWANCE) transferAllowance(tax_allowance - DEFAULT_ALLOWANCE); else transferAllowance(tax_allowance - ALLOWANCE_OAP); spouse.isMarried = false; spouse.spouse = null; spouse = null; isMarried = false; } /* Transfer change of the tax allowance from this person to his/her spouse */ //@ requires spouse != null; //@ requires spouse.spouse == this; //@ requires spouse != this; //@ ensures tax_allowance == \old(tax_allowance) - change; //@ ensures spouse.tax_allowance == \old(spouse.tax_allowance) + change; void transferAllowance(int change) { tax_allowance = tax_allowance - change; spouse.tax_allowance = spouse.tax_allowance + change; } /* Taxpayer has a birthday and the age increases by one */ // @ensures age == \old(age) + 1; // @ensures age >= 65 ==> tax_allowance <= ALLOWANCE_OAP; // @ensures age < 65 ==> tax_allowance <= DEFAULT_ALLOWANCE; void haveBirthday() { age++; } }