Lecture 13: Abstraction Functions & Rep Invariants

1 Invariants

  • The most important, property of a good abstract data type is that it preserves its own invariants
  • An invariant is a property of a program that is always true, for every possible runtime state of the program.

1.1 Immutability

Imutability is an example of invariants.

  • Avoid directly access the fields(private, final in java). That is called representation exposure , meaning that code outside the class can modify the representation directly.
  • In general, you should carefully inspect the argument types and return types of all your ADT operations. If any of the types are mutable, make sure your implementation doesn’t return direct references to its representation. Doing that creates rep exposure.
  • An even better solution is to prefer immutable types. For example, we had used an immutable date object, like java.time.ZonedDateTime , instead of the mutable java.util.Date .
1.1.1 Immutable Wrappers Around Mutable Data Types
  • The Java collections classes offer an interesting compromise: immutable wrappers.
  • The downside here is that you get immutability at runtime, but not at compile time.

2 Rep Invariant and Abstraction Function

  • The space of representation values (or rep values for short) consists of the values of the actual implementation entities.
  • The space of abstract values consists of the values that the type is designed to support.

We can describe the relationship between these two space by give two things:

  1. An abstraction function that maps rep values to the abstract values they represent:

    AF:RA

    • Every abstract value is mapped to by some rep value.
    • Some abstract values are mapped to by more than one rep value.
    • Not all rep values are mapped.
  2. A rep invariant that maps rep values to booleans:

    RI:Rboolean

    • For a rep value r , RI(r) is true if and only if r is mapped by AF . In other words, RI tells us whether a given rep value is well-formed.

The essential point is that designing an abstract type means not only choosing the two spaces – the abstract value space for the specification and the rep value space for the implementation – but also deciding what rep values to use and how to interpret them. For example:

public class CharSet {
    private String s;
    // Rep invariant:
    //    s.length is even
    //    s[0] <= s[1] <= ... <= s[s.length()-1]
    // Abstraction Function:
    //   represents the union of the ranges
    //   {s[i]...s[i+1]} for each adjacent pair of characters 
    //   in s
    ...
}

2.1 Checking the Rep Invariant

If your implementation asserts the rep invariant at run time, then you can catch bugs early. Here’s an example tests rep invariant that all input should not be null:

// Check that the rep invariant is true
// *** Warning: this does nothing unless you turn on assertion checking
// by passing -enableassertions to Java
private void checkRep() {
    assert s.length() % 2 == 0;
    ...
}

You should certainly call checkRep() to assert the rep invariant at the end of every operation that creates or mutates the rep – in other words, creators, producers, and mutators. As a defensive practice, it should be called at every operation of your ADT.

2.2 Documenting the AF, RI, and Safety from Rep Exposure

you should write a rep exposure safety argument . This is a comment that examines each part of the rep, looks at the code that handles that part of the rep (particularly with respect to parameters and return values from clients, because that is where rep exposure occurs), and presents a reason why the code doesn’t expose the rep. Here is an example:

// Immutable type representing a tweet.
public class Tweet {

    private final String author;
    private final String text;
    private final Date timestamp;

    // Rep invariant:
    //   author is a Twitter username (a nonempty string of letters, digits, underscores)
    //   text.length <= 140
    // Abstraction Function:
    //   represents a tweet posted by author, with content text, at time timestamp 
    // Safety from rep exposure:
    //   All fields are private;
    //   author and text are Strings, so are guaranteed immutable;
    //   timestamp is a mutable Date, so Tweet() constructor and getTimestamp() 
    //        make defensive copies to avoid sharing the rep's Date object with clients.

    // Operations (specs and method bodies omitted to save space)
    public Tweet(String author, String text, Date timestamp) { ... }
    public String getAuthor() { ... }
    public String getText() { ... }
    public Date getTimestamp() { ... }
}

2.3 How to Establish Invariants

The full rule for proving invariants is: Structural induction. If an invariant of an abstract data type is:

  • Established by creators and producers.
  • Preserved by mutators, and observers.
  • No representation exposure occurs.

then the invariant is true of all instances of the abstract data type.

3 ADT invariants replace preconditions

/** 
 * @param set1 is a sorted set of characters with no repeats
 * @param set2 is likewise
 * @return characters that appear in one set but not the other,
 *  in sorted order with no repeats 
 */
static String exclusiveOr(String set1, String set2);`

We can instead use an ADT that captures the desired property:

/** @return characters that appear in one set but not the other */
static SortedSet<Character> exclusiveOr(SortedSet<Character>  set1, SortedSet<Character> set2);

Reference

[1] 6.005 — Software Construction on MIT OpenCourseWare | OCW 6.005 Homepage at https://ocw.mit.edu/ans7870/6/6.005/s16/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值