Comp210 Lecture # 5    Spring 2003

Structures continued...

We define a structure representing a brand of airplane with the followind data definition:

;; A plane_brand is:
;; (make-plane_brand symbol num num num)
;;where manufacturer is the maker of the brand,
;; speed is the cruising speed,
;; seats is the seating capacity, and service is the number
;; of miles before an overhaul is required .

(define-struct plane_brand (manufacturer speed seats service ))

; Here we create ("instantiate") some concrete brands with actual values in the fields ("instances" of the brand):

(make-plane_brand 'Boeing 550 282 15000)          ;; DC-10

(make-plane_brand 'Boeing 505 141 10000)          ;; MD-80

(make-plane_brand 'Aerospatiale 300 46 5000)     ;;ATR-72

(make-plane_brand 'Airbus 540 250 12000)            ;; A320

; We can use accessor functions to access the values stored inside an instantiation:

(symbol=? 'Boeing (plane_brand-manufacturer (make-plane_brand 'Boeing 550 282 15000)))         

(= 505 (plane_brand-speed (make-plane_brand 'Boeing 505 141 10000)))

(= 46 (plane_brand-seats (make-plane_brand 'Aerospatiale 300 46 5000)))

(= 12000 (plane_brand-service (make-plane_brand 'Airbus 540 250 12000)))

;In addition, Scheme automatically creates a comparison function that tests if its input is of that structure's type (note the use of boolean=? rather than =):

(boolean=? true (plane_brand? (make-plane_brand 'Boeing 550 282 15000)))         

(boolean=? false (plane_brand? 'Something_else))

; We can now write a function to process a plane_brand. For instance, how long can a plane fly between service overhauls?

;; serviceTime: plane_brand --> num or symbol
;; Calculates the time that a plane_brand can fly at
;; cruising speed between service overhauls.
;; Returns 'Invalid_input! if the supplied expression is not a plane_brand

(define (serviceTime brand)

(cond

[(plane_brand? brand) (/ (plane_brand-service brand) (plane_brand-speed brand))]
[else 'Invalid_input!]))    ; fail safe clause

;; Test code

(= (/ 2000 101) (serviceTime (make-plane_brand 'Boeing 505 141 10000)))
(= (/ 200 9 ) (serviceTime (make-plane_brand 'Airbus 540 250 12000)))
(symbol=? 'Invalid_input! (serviceTime 'Cessna))
Note: At this stage in the course, we will not enforce the inclusion of the fail-safe clause because of how it complicates the contracting. You may include it, but if you do, make sure that it does not violate your contract! Later in the course, we will be more strict about this.

The Push for Abstraction

In our never-ending striving for abstract representations, let's take a step back and look at the functions we've written that use structures.

What can we say about the essence of functions that work on plane_brand structures? Is there anything that is common to all such functions?

Look at the various parts of the function and what they are dealing with and express them as a design template:

(define (aFunc aPlane_Brand ... )
	(cond
		[(plane_brand? aPlane_Brand)  ...(plane_brand-manufacturer aPlane_Brand)...
                                              ...(plane_brand-speed aPlane_Brand)...
                                              ...(plane_brand-seats aPlane_Brand)...
                                              ...(plane_brand-service aPlane_Brand)...]
    	[else error_result]))
	

In words, a function that works on a plane_brand

  1. Takes a plane_brand as one of its input parameters (Hey! CS is all about expressing the obvious in code!)
  2. Checks that the input is of the right type (never trust the user).
    1. Does processing that depends on the attributes of plane_brand (yeah, yeah, yeah...)
    2. Has well-defined behavior for invalid inputs.

     

In light of these earth-shaking revelations, we modify our original design recipe:

New Design Recipe

  1. Data analysis -- how can we represent the data in our program? What templates are implied?
  2. Data examples
  3. Contract, purpose and header
  4. Test cases
  5. Code body -- how does the data analysis create a template for the code body?
  6. Run tests.

 

A Higher Abstraction...

Let's define another type of structure:

;; An auto_brand is:
;; (make-auto_brand symbol num num )
;;where manufacturer is the maker of the brand,
;; seats is the seating capacity, and warranty is the number
;; of miles covered by the warranty.

(define-struct auto_brand (manufacturer seats warranty))

auto_brand and plane_brand are different, but yet similar in some ways. Ignoring specifics for a minute, let us consider the simple (simple is always good in programming) fact that both represent brands of some sort of vehicle. How can we represent that?

We'd like to say something like this sort of abstract data definition:

;; A vehicle_brand is struct that could be
;; - an auto_brand or

;; - a plane_brand

So, let's just say it like that, ok?

Now let's consider a function on vehicle_brand. Let's modify our original serviceTime function:

     ;; vehicleServiceTime: vehicle_brand --> num or symbol
     ;; Calculates the time that a vehicle_brand can go at
     ;; cruising speed between service overhauls.
     ;; Returns 'Invalid_input! if the supplied expression is not a vehicle_brand

     (define (vehicleServiceTime brand)
         (cond
            [(plane_brand? brand) (/ (plane_brand-service brand)
                                     (plane_brand-speed brand))]
            [(auto_brand? brand) (/ (auto_brand-warranty brand) 55)]
            [else 'Invalid_input!]))  ; fail safe clause

     ;; Test code -- the old tests should still work
     (= (/ 2000 101) (vehicleServiceTime (make-plane_brand 'Boeing 505 141 10000)))
     (= (/ 200 9 ) (vehicleServiceTime (make-plane_brand 'Airbus 540 250 12000)))
     (symbol=? 'Invalid_input! (serviceTime 'Cessna))

     ;; Some new tests
     (= (/ 10000 11) (vehicleServiceTime (make-auto_brand 'Toyota 4 50000)))
     (= (/ 6000 11) (vehicleServiceTime (make-auto_brand 'GM 2 30000)))

We can see that the data analysis of an abstract data structure affects our design template:


     (define (aFunc aBrand ... )
        (cond
            [(plane_brand? aBrand) ...(plane_brand-manufacturer aBrand)... 
                                   ...(plane_brand-speed aBrand)...
                                   ...(plane_brand-seats aBrand)...
                                   ...(plane_brand-service aBrand)...]
            [(auto_brand? aBrand) ...(auto_brand-manufacturer aBrand)... 
                                  ...(auto_brand-warranty aBrand) ...
                                  ...(auto_brand-seats aBrand)]
            [else error_result]))
			

This is called "Data-Driven Design". Notice how the code body is practically writing itself, based on the data analyis.

Points To Ponder...

 

 

 

 

 

 

 

 

 

©2003 Stephen Wong