| CSC 161.01 | Grinnell College | Fall, 2019 |
![]() |
CSC 161.01
Imperative Problem Solving with Lab |
![]() |
This reading begins a transition to object-oriented problem solving, assuming background in functional problem solving (with Scheme) and imperative problem solving (with C). The reading proceeds in three main sections:
A basic motivation for object-oriented (OO) problem solving involves managing complexity. Rather than define various data structures independently from operations, OO problem solving packages data together with the operations that operate on them.
Consider a simple class that would maintain information about a course (e.g., CSC 207). Each object in the class might have the following characteristics:
Higher-order procedures provide one way to implement an object within Scheme. Within a higher-order procedure, a let or let* provides a mechanism to define the primary data fields.
One way to define fields within a higher-order procedure follows the style of CSC 151; the fields may be placed within a locally-defined vector content, and each index of the vector can have a specified interpretation:
(define course
(lambda (subj . other-data)
(let (;; content: listing of private data as fields within a vector
(content (make-vector 4))
;;define positions within content as data elements
(subject 0)(number 1)(credits 2)(title 3))
With this approach, the course subject can be access with
(vector-ref content subject) ;; retrieve subject data from index 0 (vector-set! content subject "CSC") ;; set subject to CSC
Within this framework, operations can be given as parameters to the defined higher-level procedure. For example, the following scenario shows how two courses might be defined and used:
;; initialize two courses, with higher-order procedure course (define myCourse (course "CSC" 207 4 "Algorithms and Object-Oriented Design")) (define yourCourse (course "Math")) ;; test of initialization, toString, and extractor methods (myCourse 'toString) (yourCourse 'getSubject) (yourCourse 'getNumber) (yourCourse 'getTitle) (yourCourse 'getCredits) ;; set fields (yourCourse 'setNumTitle 131 "Calculus I") (yourCourse 'setCredits 4) ;; print results of modification (yourCourse 'toString)
To clarify this use of a higher-order course procedure, the course procedure provides a mechanism to define two objects. In the example, the definition of myCourse allows a user to define an object with four types of data: subject, course number, credits, and title. The definition of yourCourse allows a user to define an object with just a subject (default values are given for the other fields).
Program course-1.ss provides the full Scheme code, with testing. As this program illustrates, data are stored in fields of a vector, and vector-set! is used to adjust those fields, as appropriate.
Rather than store all data fields within a single vector, a second approach uses separate local variables for each field. In this approach, field variables can be defined with default initialization at the beginning of the higher-order course procedure:
(define course
(lambda (subj . other-data)
(let (;; fields: listing of private data
(subject subj) ;; the subject or department name
(number 0) ;; the course number
(credits 0) ;; the number of credits
(title "")) ;; the name of the course
The rest of this procedure is similar to the first approach, except that the variables can be accessed directly (rather than through the vector) and variables are changed with set! rather than vector-set!.
Program course-2.ss provides the full Scheme code for this alternative approach.
In reviewing these two approaches for defining objects in Scheme, be sure that you can answer the following questions:
These notes highlight the in-class discussion of a Course class, as defined in Course.java. These notes are not designed to be comprehensive. Rather, they provide a brief commentary on the program. You may want to consult more substantive sources for a more complete review of the Java programming language. In what follows, the commentary starts with the first lines of code and proceeds through to the end.
Java programs identify comments in two ways:
Comments may be enclosed in /* and */. That is, the characters /* are considered to be the start of a comment, and the comment is completed with the characters */. Such a comment may be part of a line or extend over multiple lines. This type of comments follows exactly the style as comments in C.
Whenever two slash characters // appear on a line, the rest of the line is considered as a comment. Thus, // in Java is analogous to a semicolon ; on a line of Scheme. (This type of comment is also allowed in C++, and thus is often recognized by C compilers. However, Standard C does not allow this type of comment.)
Java organizes classes into modules, called packages. When writing small programs, such an organization may seem unnecessary. However, Java was designed for large-scale applications, in which there may be a very large number of classes. In that context, it is important to keep track of the names of various classes, and there is potential for the developers of one part of the program to use the same class names as have been specified by developers of another part. That is, developers of different parts of a program might use the same class names, and Java would need to determine which class was meant at each stage. Thus, the designers of Java decided to organize classes into packages, so the classes within one package could be distinguished from those in another.
The package name of a class is specified with the statement
package course;
Within Unix and Linux systems, the convention is that a package name corresponds to a directory, and all classes within a package are stored within this designated directory.
Within the context of a package, names may be easy to identify. However, within a broader programming context, Java employs a naming convention for packages that reflects the directory structure. Thus, the Java "standard" suggests that you follow a similar style to a Web URL, although the ordering of the elements is reversed. For example, some of my sample Java programs might be in a package that starts with
edu.grinnell.cs.walker.java.examples
Java supports object-oriented problem solving, and all programs in Java begin with classes and objects. Thus, each program component is a class, and a file begins with the declaration of one class. In the example, the class Course is identified as public, meaning that any application is allowed to utilize this class in its work.
Note the file name Course.java has the same name as the class (with .java appended at the end).
Unlike Scheme, capitalization matters in Java. Thus, a class Course is not the same as a class course.
While not required, a common Java convention is that the names of classes start with a capital letter (e.g., Course), while the names of data fields and methods begin with a lower-case letter.
As with C, variables in Java must be declared, and the type of the variable must be specified.
In Java, fields must be declared within a class or method before the fields are used.
Java also requires that we must specify the type of data to be stored in every variable. Some common data types are:
In class course, fields subject and title are used to store character strings, while number and credits store integer data.
Whenever objects are created from classes, all fields are initialized.
Methods for initializing data have the same name as the class.
Initialization may be done in several ways — using different methods, provided the constructor methods have different parameters.
In the example, Course has two constructor methods — both called Course. With the first, one supplies a subject parameter, and other fields are set to 0 or the null string. The second constructor requires the programmer to specify data for all four fields.
If a constructor does not explicitly initialize a field, or if no constructor is provided by the programmer, then Java will initialize all fields according to various default values. For clarity and to avoid oversights, programmers should get into the habit of supplying constructors and explicitly initializing all fields.
Extractor methods return data from various fields, while modifier methods change the values stored in those fields.
Just as in Scheme, an object contains some methods which are available for applications, and an object also may include helper methods which are for local or internal use only. For example, in husk-and-kernel processing, the husk might be generally available, while the kernel would not be.
As with C procedures, the definition of every method indicates either what type of data are returned by the method or that no data are returned. In the example,
Methods may or may not have parameters in Java, just as in Scheme and C. When no parameters are given, method names are followed by parentheses ( ), indicating a procedure or method with no parameters. When parameters are to be supplied, the method definition indicates the names and types of those parameters. Like C, but unlike Scheme, Java methods require the programmer to specify what type of data will be supplied as parameters.
In Java, as in C, the brackets { and } serve as begin and end markers. Thus, brackets in Java have a similar function to parentheses in Scheme.
Java contains strings and string operations that are analogous to those in Scheme.
Java provides extensive capabilities for input and output through predefined class libraries. To get started, the simplest approach for printing involves a System object that is established whenever a Java program is run. To print, one constructs a desired string as parameters to methods print and println:
System.out.print ("counting: 1, " + "2, " + "3, ");
System.out.println ("..., done");
System.ut.println ("next line");
When executed, these two lines produce the following output:
counting: 1, 2, 3, ... done next line
In this example, several strings (e.g., "counting: 1, ", "2, ", and "3, ") are concatenated to form a single large string, and this string is printed. When using print, no "new line" character is sent to the terminal. Thus, printing for the next statement (println) continues on the same line. The println method always move to a new line when it has finished printing, so subsequent printing starts on the following line.
Once we defined classes in Scheme, we tested and used them in separate code, and Java also allows classes to be used by other classes and programs. In addition, Java allows any class to have a main method, which can be used to run a program based on the given class. In this regard, Java's main method is analogous to C's main procedure.
public static void main (String[] args)
throws Exception {
Here, public and void mean just what has been described earlier:
As with C, Java programs may take command line arguments, and such values are handled by specifying an array of strings as parameters (String[] args). While this capability may be useful in running programs, we will not utilize main's parameters for now.
main methods sometimes encounter unusual circumstances in processing that require special handling. The phrase throws Exception provides a mechanism to address these circumstances. Not all main methods face such conditions, but including throws Exception in the code anticipates any potential troubles, should they arise.
Technically, Java requires that a main method belongs to the class; there are not separate main methods for each object. This gives rise to the descriptor static in the declaration of main. While this will become clear over time, for now, it is strongly suggested that you consider the header
public static void main (String[] args)
throws Exception {
as an idiom to be used when defining a main method.
Once objects are declared and initialized, their methods may be utilized by specifying the object and the desired method — separated by a dot. Thus, myCourse.toString() specifies the toString method of myCourse, while yourCourse.getCredits() references the getCredits method of object yourCourse
This document is available on the World Wide Web as
http://www.walker.cs.grinnell.edu/courses/207.sp12/readings/reading-intro-objects.shtml
|
created 3 April 2001 last revised 22 January 2012 |
|
| For more information, please contact Henry M. Walker at walker@cs.grinnell.edu. |