Computer Science Department

Computer Science Department

Introduction to Programming 2

Brief Summary Notes by Steve Benford

Chapter 1 : Programming in the Large

Contents

1.1. Goals of the course

PR1 taught you how to write relatively small-scale computer programs to solve a variety of problems. As a result, you should have developed some basic problem solving skills as well as a working knowledge of C++.

So far, you have programmed on your own, producing one-off "stand-alone" programs. This is a far cry from real-world programming which often involves teams of programmers producing massive and complex systems over a long period of time. PR2 changes our focus away from the microscopic nuts-and-bolts level of small-scale programming towards programming in the large - i.e. solving large problems as part of a programming team.

As with PR1 the course will cover general programming concepts. It will also introduce new features of C++ to support these concepts. Regular coursework will be a central part of the course. More specific goals include:

As you have probably already noticed, the hardest part of programming is often problem-solving, not writing code. This course will attempt to further develop problem solving as well as programming skills. We will also introduce some "software tools" which support the general development of programs.

You should understand that this course does not tell the whole story. First, we do not look at many more advanced programming techniques (e.g. fully object-oriented programming). These are left for the second year course on Object-Oriented Design. Third, we do not cover the team-work and project-management aspects of large-scale system building. These are addressed by the Group Projects in the second year.

1.2. Overview of PR2

PR2 is divided into the following chapters.

  • 1. Introduction to programming in the large. Discussion of the requirements of building large scale commercial systems in programming teams. Introduction to Data Abstraction as a key technique.
  • 2. C++ Classes as a way of implementing Abstract Data Types. Terminology and structure of classes and objects. Simple examples: the Counter, Money and Set classes.
  • 3. Interacting classes. Solving more complex problems by building classes which work together. At this level, programs can be seen as a set of interacting, but discrete objects. The main example is a Cashpoint simulator which interacts with Account and Money classes.
  • 4. Better interfaces to classes. Making your classes easier for other programmers to use. Specific issues will include operator and function overloading as well as the use of references. Examples include a Point class representing two dimensional coordinates.
  • 5. Pointers revisited. An in depth exploration of pointers, building on the work of PR1. If used carefully, pointers provide us with great flexibility for solving complex problems. This chapter will give thorough coverage of how to declare and manipulate pointers.
  • 6. Building dynamically expandable data types. How to use pointers to gain greater control over memory usage and so become free of the fixed size limitation inherent in data types such as arrays. Examples include a resizeable array and a String class for manipulating text.
  • 7. Linked data types. The construction of complex objects which consist of linked components. The main example will be a Linked List data type representing an arbitrarily long list of objects.
  • 8. Case study: the Line Editor. This chapter will draw the contents of the course together by looking at the design and implementation of a simple Line Editor which can be used to edit files.

    1.3. Commercial programming

    Building real systems in a commercial/industrial environment is very different to the kind of programming you have done so far :-

  • Programs are many times larger (maybe millions of lines of code).
  • As a result of their size, programs are usually written by programming teams, not by individuals. This means that they must be Modular in structure (i.e. easily divided into distinct components).
  • Programs should have a long lifetime (not just 1 week) during which they need to be maintained, maybe repaired and/or upgraded.
  • New programs should be built on existing code because i) re-using existing code reduces development time and increases profit ii) new products often need to be compatible with old ones.
  • Programs need to work properly. This is obviously true for programs which control dangerous machines (e.g. fly-by-wire aircraft) or manipulate huge sums of money. Of course, it really applies to all programs as the company's reputation is critical to good business. The number of bugs in code should be minimised and, when they occur (because they always do), they should be easy to locate and fix.

    The discipline of programming in such an environment is called Software Engineering. Its main goals are to produce systems which are modular, maintainable, extendable, work properly and make maximum re-use of existing code.

    1.4. Procedural Abstraction

    The key to building such systems is ABSTRACTION. We have already seen on the CUA course that the history of programming languages is one of increasing abstraction. Abstraction allows us to form a view of a problem which considers only necessary details and hides away unnecessary nitty-gritty. Abstraction can also be used to give different people different views of the same problem. You have already come across this in PR1.

    For example, imagine that I write a C++ function called power which raises one number to the power of another. I might show you the function heading with suitable comments describing what the function does. You would then know how to use it in your own program.

    Note that you don't have to know how it is implemented! In other words, you have an abstract view of the function. I then have to write a specific implementation. Here are two different ones.

    Note that you are unware of which implementation I use. Even more importantly, I can change the implementation - perhaps make it more efficient - and your code won't have to be changed. We call this procedural abstraction.

    Put more formally, procedural abstraction is used to define an interface between the user and the implementor of a function resulting in more modular code.

    1.5. Data Abstraction

    Data Abstraction takes these ideas much further. Instead of defining a single function, a whole new data type is defined.

    Each language provides a basic set of types (e.g. float, int, char in C++) and gives the user operations for manipulating variables of these types (e.g. + - * etc). Data Abstraction allows the definition of new types, complete with a set of operations or functions, which appear as if they were part of the language. We call these Abstract Data Types (ADTs).

    The idea is that a new ADT is defined so that its users see an interface which provides an abstract view of the type and only its implementors see its internal details. The interface is defined by a set of functions which give access to the type. It is only possible to access the type through its functions.

    We can show this by the following picture:

    Several points need emphasising:-

  • We talk about each ADT having a user and an implementor. These may represent different members of a programming team. Thus ADTs give us a way of breaking a program into a modular structure.
  • The functions exactly specify the interface to the type (i.e. how it can be used).
  • The internal details (e.g. any data) cannot be accessed apart from through the functions. In other words, the functions protect the ADT from being tampered with, as well as protecting the user from having to know internal details. We call this encapsulation.
  • Encapsulation reduces the chances of bugs occurring and makes them easier to locate when they do. If a data type gets corrupted you know that it must have been one of its interface functions that caused the problem.
  • If we define a general enough set of functions, an ADT can be re-used in many different situations.

    Thus, ADTs will form the basis of our approach to programming in the large. Notice, that they represent a general technique, not a specific part of any particular language (although several languages provide good support for building them). In the next chapter we will see how to realise ADTs in C++ using the new mechanism of classes.


    Notes converted from troff to HTML by an Eric Foxley shell script, email errors to me!