Objects as Abstract Data Types
From Real Software Documentation
Aim
In this lesson, we will begin looking at object-oriented programming. We begin this by examining how and why we should create our own data types.
Contents |
What is an Abstract Data Type?
Formally, an Abstract Data Type (ADT) consists of a set of operations, which are the only way for other code to access some particular data. The ADT defines a type, and the data is said to be of that type.
The benefit that this provides is that it separates implementation from interface. In traditional object-oriented programming terms, this is called encapsulation. You may also hear that an ADT abstracts the details of data, and provides information hiding.
Encapsulation provides three benefits:
- We can develop and debug the Abstract Data Type separately from the rest of the program;
- We can change the implementation of the Abstract Data Type without having to change any code that calls it; and
- We can provide access to several similar types of data sources from one set of code, without addressing the details that distinguish the types of data.
These benefits are a first glimpse at something we are going to be looking at repeatedly throughout this course: we want to be able to break a complex program down into well-separated parts that can be developed, debugged, improved, and changed separately.
The second benefit also allows us to approach development in an incremental fashion: we can implement an ADT in a quick-and-dirty fashion in order to get the program working, then go back later and make it faster, use less memory, or provide extra features.
Pre- and Post-Conditions
We saw preconditions and postconditions briefly in the last lesson. You should employ these concepts in defining an Abstract Data Type: you should state as simply and accurately as possible what each operation provided by an Abstract Data Type does, in terms of what should be true before you execute that operation, and what will be different afterward.
“Object-oriented” means built-in support for ADTs
If you have used other programming languages before, you should know that you can employ the benefits of ADTs in virtually any programming language. However, object-oriented programming Languages such as Realbasic provide built-in features that explicitly support creating Abstract Data Types, as we will see.
Improving The Word Counter with ADTs
- Make a copy of the Word Counter project. Open it.
We are going to make a version of the Word Counter that counts the text on the Clipboard. We are going to make it get the text from an Abstract Data Type.
- In the Project Editor, click on the Add Class button.
You will then see a new item in the Project Editor, and the Properties pane will be ready for you to set its properties. - Change the name of the new class to “CharacterSource”.
You have just declared a new type of data you can store in variables and properties in your program. The next step is to provide it with suitable methods and properties so we can use it as a source of data for our word counter.
- Double-click on the icon for the CharacterSource class, to open its Code Editor.
- Click on the Add Property button, and give the new property the name “ClipBoardSource” and data type of “ClipBoard”.
- Click again on Add Property and give the new property the name “CurrentPosition” and data type of “Integer”.
The Project Editor should now look like this.
Object References versus Scalars
This is the first time we’ve stored an object in a property or a variable. The ClipBoard type that we just declared for our ClipBoardSource property is an object, which is a different kind of thing to the strings, numbers and Booleans we’ve kept in properties and variables until now.
Properties in Real Studio can store two quite different types of things: scalars and object references. Scalars just have a value. Once you’ve declared the variable, you can start working with its value.
An object reference is different: it tells Real Studio where in its memory to locate an object. When you declare the variable or property, you’ve just declared somewhere to keep an object’s location (and you’ve said what type of object will be there), but you haven’t actually created an object. A variable or property declared to be an object initially has the special value Nil, meaning it points at nothing.
Before you can actually do something with an object, you have to get the variable or property to refer to it. In this case, we need to ask Real Studio to create an object, and provide a reference to it that we can store in our variable.
This is the only way to access objects in Real Studio. Although it may seem a little strange, this is actually a natural way to work with objects, and it will soon become second nature.
- Click the Add Method button, and name your new method “Begin” and don’t give it any parameters or a return value. Set its code to:
CurrentPosition = 0
ClipBoardSource = New Clipboard
This method must be called before our Abstract Data Type can be used (we’ll see a better way to initialize an object in a later lesson).
- Add the following methods to the class:
Function CurrentChar as String
//This method is not called more often than the length of the clipBoard text
//Post: each time this method is called, the characters on the clipBoard text are returned in order
CurrentPosition = CurrentPosition + 1
Return Mid (ClipBoardSource.Text, CurrentPosition, 1)
Function Finished as Boolean
//Post: return true if the last call to CurrentChar returned the last character of the clipBoard text, else return false
Return (CurrentPosition > Length+1)
Function Length As Integer
//Post: the length of the text on the ClipBoard is returned
Return Len (ClipBoardSource.text)
Each of these functions takes no parameters but each has a return value.
You’ll probably need to look up a few Real Studio features (such as Len and Mid, as well as the features of the ClipBoard object) to follow this code. Notice that we can just return the results of a Boolean expression (in the Finished function).
Can you see how the methods we’ve implemented here provide everything we need to loop through the string on the clipboard? Notice also that any code calling these methods doesn’t need to know anything about the source of the string.
- Add a property to the Window and name it “ClipBoardSource” and give it the data type of “CharacterSource”.
- Change the parameter passed to IsWordCharacter to and change its code to:
//Post: If c is a letter or number, return true, else return false
Return (c>="0" and c<="9") or (c>="A" and c<="Z") or (c>="a" and c<="z")
- Modify your CountWords method to read:
//Post: Word array contains all of the words in ClibBoardSource;
//Count array contains corresponding count of those words in ClipBoardSource
Dim InWord As Boolean
Dim c, StringBuffer As String
// Initialize ClipBoardSource
ClipBoardSource = new CharacterSource
ClipBoardSource.Begin // c Invariant, starting *before* first character
InWord = false
//Inword Invariant
StringBuffer = "" //StringBuffer Invariant
while not ClipBoardSource.Finished
//Invariants:
// c: c is the next unprocessed character in ClipboardSource
// StringBuffer: StringBuffer holds the string of characters that will be the next word to be added to our list;
// after it is added, or between words, this string is empty
//Inword: InWord is true if the counter character of Source.text was IsWordCharacter
//Note: Other than StringBuffer, we only need to act on word boundaries
c = ClipBoardSource.CurrentChar //c invariant
if InWord then
if not IsWordCharacter (c) or ClipboardSource.Finished then //Word End; emit word
AddWord StringBuffer //StringBuffer Invariant
StringBuffer = "" //StringBuffer Invariant
InWord = false //InWord invariant
else
StringBuffer = StringBuffer + c
end if
else //not InWord
If IsWordCharacter (c) then //WordBegin; start buffering
InWord = true //InWord invariant
StringBuffer = StringBuffer + c
if ClipBoardSource.Finished then
AddWord StringBuffer
end if
end if
end if
Wend
You can see here that we can call methods and functions from classes we create, exactly the same as we do with the built-in classes.
It is important to recognize the difference here between the type or class (CharacterSource) and an instance of that type (ClipBoardSource). There is an analogy in real life: Tom Cruise is an instance of the actor class; or New York is an instance of the city type. Computer programmers might also use a kind of shorthand and say that “New York” is an instance of “city”.
The While Loop
We’ve introduced a new type of loop above: a While loop. It has a similar form to a For loop, but it starts with a While statement — consisting of the word While followed by a Boolean condition — and ends with the word Wend. It tests the condition, executes the code inside the loop, and repeats these two steps over and over until the condition is false.
How is the ADT Code an Improvement?
We’ve changed the source of the text for our word counter, but that’s not an improvement: it’s a feature change. How is this method of writing the word counter an improvement?
When we write computer code, we generally want to do these things:
- Correctly implement the desired behavior;
- Implement the desired behavior, fully debugged, as quickly as possible; and
- Make the code as easy to modify as possible. We will sometimes[note 1] also want to:
- Make the code run using a minimal amount of some resource (time, memory, bandwidth and so on).
The code in this project is an improvement over the code in the last project because it better satisfies the easy to modify requirement. This benefit isn’t immediately apparent, but we will see in coming lessons how easy it is now to make our word counter work with different data sources.
This is a very good general design principle: any data structure you build should come with a layer of interface code. This code should provide the features the rest of the program needs in order to use that data, but should hide all details of how the data is actually stored.
The ADT Advantage
It’s important to see at this point what we’ve done by using an ADT for this project: CountWords needs to know nothing about the source of the words it is counting. Instead, we’ve pared down the features it needs to do its job to the absolute minimum. Now, we can count the words in any source of text by implementing a very simple interface to that text. We need not modify CountWords at all. We can, in a sense, “plug in” a source of text to CountWords. In this case, it is the text on the Clipboard.
We will see in coming lessons how cleanly object-oriented programming supports this ability to “plug things together”.
Exercise
There is another data structure in our program: the pair of arrays that keeps the words and their counts. Try to implement this as an ADT.
References
- Notes
- ↑ It is a very common mistake among programmers to obsess about “efficiency” in a lot of situations where it just doesn’t matter.
