Lab15: Forcing C to be Object-Oriented

...and then [Men] would or could be made to mate with Orcs, producing new breeds, often larger and more cunning. There is no doubt that long afterwards, in the Third Age, Saruman rediscovered this, or learned of it in lore, and in his lust for mastery commited this, his wickedest deed: the interbreeding of Orcs and Men, producing both Men-orcs large and cunning, and Orc-men treacherous and vile.
--- J.R.R. Tolkien, Morgoth's Ring

How can we tolerate these indignities [being forced to program in Fortran or C equivalents because more creative programming languages are supressed]? The frustratingly simple answer is the universal nature of programming languages---the fact that one can program in any one of them what can be programmed in any other. We are able to clever our way out of any programming box. The more difficult the task, the more pride we can take in the accomplishment.
--- Richard Gabriel and Ron Goldman, "Mob Software: The Erotic Life of Code"

The goal of this lab is to practice using function pointers to emulate in C the object oriented features of encapsulating (data and functionality together), subtyping, and polymorphism.

1. Introduction

The first C++ compilers simply translated C++ programs to C source, which was then fed into a C compiler. Also during the early days of Java, someone bothered to write a Java-to-C compiler (rather than compiling Java to bytecode/classfiles).

How is a translation like this possible, since C lacks so many of the core elements of a language like Java? For one thing, C's programming concepts aren't much different from how the computer (at the hardware level) actually works--- and obviously Java programs can be run on a real computer. Besides, the Church-Turing thesis tells us that all models of computing are equivalent to each other.

As we began to imagine in class yesterday, function pointers help a lot for doing something in C that looks like polymorphism. (In fact, it is polymorphism, just not subtype polymorphism.) In this lab, we will fill out the details.

2. Problem background

The problem/example we're going to work on is something I use in Programming I as an early example of polymorphism: Have several types that represent different kinds of mathematical functions: polnomials, rationals, exponentials, step functions... They all have certain operations: evaluate the function at an x value, find a derivative, evaluate a definite integral...

Here's the interface that defines the supertype:

/**
 * Function.java
 * 
 * This provides a common interface and super type for all
 * kinds of functions we wish to model.
 * 
 * @author Thomas VanDrunen
 * Wheaton College, CS 241, Fall 2005
 * In-class example
 * Oct 24, 2005
 */

public interface Function {


    /**
     * Evaluate this function for a given value of x.
     * @param x The value at which to evaluate the polynomial.
     * @return The value of this polynomial at x
     */
    public double evaluate(double x);

    /**
     * Find the derivative of this function.
     * @return The function that is the derivative of this one
     */
    public Function derivative();

    /**
     * Calculate the definite integral of this function, given upper and lower
     * bounds. 
     * @param lower The x value at which the region begins; the lower bound
     * @param upper The x value at which the region ends; the upper bound
     * @return The value of the definite integral
     */
    public double integrate(double lower, double upper);
}



/**
 * Polynomial.java
 *
 *  Class to model polynomials ...
*/

import java.util.Scanner;

public class Polynomial implements Function{


    /**
     * The coefficients of the terms in this polynomial
     * (the item at position i is the coefficient of x^i)
     */
    private double[] coefficients;

    /**
     * Constructor. Set the (instance variable) coefficient
     * array to a copy of the (formal parameter) one given.
     * @param coeffs An array containing the coefficients of
     * this polynomial.
     */
    public Polynomial(double[] coeffs) {   
        coefficients = new double[coeffs.length];
        for (int i = 0; i < coefficients.length; i++)
            coefficients[i] = coeffs[i];
    }

    /**
     * Constructor. Query the user for the coefficients.
     */
    public Polynomial() {
        Scanner keyboard = new Scanner(System.in);  // for user input
        System.out.print("Please enter the degree");

        int degree = keyboard.nextInt();   // the polynomial's degree
        keyboard.nextLine();

        coefficients = new double[degree + 1];
        
        for(int i = 0; i < coefficients.length; i++) {
            System.out.print("Please enter the " + i + "th degreed coefficient--> ");
            coefficients[i] = keyboard.nextDouble();
            keyboard.nextLine();
        }
    }
    /**
     * Evaluate this polynomial at the given x-value.
     * Loop through the coefficients, keeping a running power of
     * x and a running result.
     * @param x The value at which we're evaluating this polynomial.
     * @return The value of the polynomial at the given x value.
     */
    public double evaluate(double x) {   

        double evaluation = coefficients[0];  // the value (result)
                                              // (we initialize it to the constant term)
        double xpow = x;  // "running power" of x-- x^i on the ith iteration.

        for (int i = 1; i < coefficients.length; i++) {
            evaluation += xpow *  coefficients[i];
            xpow *= x;
        }
        
        return evaluation;

    }

    /**
     * Calculate the derivative of this polynomial.
     * Make a new array (one unit smaller), each element
     * equal to the equivalent element in the original array
     * one position over, times the other position's exponent.
     * @return The polynomial that is the derivative of this one.
     */
    public Function derivative() {      

        // the new coefficients
        double[] diffCoef = new double[coefficients.length - 1];

        for (int i = 0; i < diffCoef.length; i++)
            diffCoef[i] = coefficients[i+1] * (i + 1);

        return new Polynomial(diffCoef);
    }


    /**
     * Calculate an antiderivative (indefinite integral) of 
     * this polynomial. Compare with the algorithm for 
     * differentiating.
     * @return A polynomial that is an antiderivative of this one
     */
    private Polynomial antidifferentiate() {
        // the new coefficients
        double[] antidiffCoef = new double[coefficients.length + 1];

        for (int i = 1; i < antidiffCoef.length; i++)
            antidiffCoef[i] = coefficients[i-1] / i;

        return new Polynomial(antidiffCoef);
    }


    /**
     * Compute a definite integral of this polynomial.
     * Find the indefinite integral, evaluate at a and b, and
     * subtract.
     * @param a The lower bound
     * @param b The upper bound
     * @return The definite integral over the given bounds.
     */
    public double integrate(double a, double b) {     
        Polynomial antiDerivative = antidifferentiate();
        return antiDerivative.evaluate(b) - antiDerivative.evaluate(a);
    }

    /**
     * Compute a string represenation of this polynomial.
     * @return A string displaying this polynomial.
     */
    public String toString() {    

        String toReturn = "" + coefficients[0];
        for (int i = 1; i < coefficients.length; i++)
            toReturn += " + " + coefficients[i] + "x^" + i;
        return toReturn;
    }
}




/**
 * Exp.java
 * 
 * Class to model functions in the form f(x) = c e^x.
 * 
 * @author Thomas VanDrunen
 * Wheaton College, CS 241, Fall 2005
 * In-class example
 * Oct 24, 2005
 */
public class Exp implements Function {

    /**
     * The linear coefficient of this exponential expression
     */
    private double coefficient;

    /**
     * Constructor.
     * @param coefficient The coefficient.
     */
    public Exp(double coefficient) {
        this.coefficient = coefficient;
    }

    /**
     * Evaluate this function for a given value of x.
     * Raise e to the given power and multiply by the coefficient.
     * @param x The value at which to evaluate the polynomial.
     * @return The value of this polynomial at x
     */
    public double evaluate(double x) { 
        return coefficient * Math.pow(Math.E, x); 
    }

    /**
     * Find the derivative of this function.
     * This is its own derivative.
     * @return The function that is the derivative of this one
     */
    public Function derivative() { return this; }

     /**
     * Calculate the definite integral of this function, given upper and lower
     * bounds. 
     * Since this is its own antiderivative, simply evaluate at the upper and lower
     * bounds and take the difference.
     * @param lower The x value at which the region begins; the lower bound
     * @param upper The x value at which the region ends; the upper bound
     * @return The value of the definite integral
     */
    public double integrate(double lower, double upper) {
        return evaluate(upper) - evaluate(lower); 
    }
}




/**
 * Step.java
 * 
 * This class models a step function,
 * providing support for evaluation, derivation, and integration.
 * 
 * @author Thomas VanDrunen
 * Wheaton College, CS 241, Fall 2005
 * In-class example
 * Oct 24, 2005
 */

import java.util.*;

public class Step implements Function {


    /**
     * The value of x at which the step should occur.
     */
    private double stepPoint;

    /**
     * The value of the function after the step.
     */
    private double stepLevel;

    /**
     * Constructor based on a given step point and step level.
     * @param stepPoint The x value at which the step occurs
     * @param stepLevel The value of the function after the step
     */
    public Step(double stepPoint, double stepLevel) {
        this.stepPoint = stepPoint;
        this.stepLevel = stepLevel;
    }

    public double evaluate(double x) {
        if (x < stepPoint) 
            return 0;
        else
            return stepLevel;
    }

    public Function derivative() {
        double[] zero = { 0.0 };
        return new Polynomial(zero);
    }

    public double integrate(double lower, double upper) {
        if (lower == upper) return 0;
        else if (lower > upper) return - integrate(upper, lower);
        else if (upper < stepPoint) return 0;
        else if (lower > stepPoint) return stepLevel * (upper - lower);
        else return stepLevel * (upper - stepPoint);
    }
}

I, read the pre-lab

Last modified: Wed Apr 25 16:27:52 CDT 2012