CS374: Programming Language Principles - Code Structure

Activity Goals

The goals of this activity are:
  1. To explain the programming language constructs of expressions
  2. To explain the programming language constructs of conditionals
  3. To explain the programming language constructs of functions
  4. To explain the programming language constructs of exceptions
  5. To relate complex data structures to their position in memory and pointer- or reference-based representation in memory

Supplemental Reading

Feel free to visit these resources for supplemental background reading material.

The Activity

Directions

Consider the activity models and answer the questions provided. First reflect on these questions on your own briefly, before discussing and comparing your thoughts with your group. Appoint one member of your group to discuss your findings with the class, and the rest of the group should help that member prepare their response. Answer each question individually from the activity on the Class Activity Questions discussion board. After class, think about the questions in the reflective prompt and respond to those individually in your notebook. Report out on areas of disagreement or items for which you and your group identified alternative approaches. Write down and report out questions you encountered along the way for group discussion.

Model 1: Assignment Expressions

1
2
3
4
5
6
7
8
9
int x = 5;
 
x = x + 1;
 
if(x == 6) {
    x = printf("%d\n", x); // is this legal? 
}
 
// x + 1 = x;

Questions

  1. In what contexts do you see x being used in this program? How about the equals sign?
  2. Why is there a = in some instances but a == in others? What would happen if the x == 6 were replaced with x = 6? How does this compare to other languages?
  3. Which x variable uses would be referred to as l-vals, and which as r-vals?

Model 2: l-val and r-val Semantics

1
2
3
4
5
6
7
8
9
int[] heights = {48, 42, 65, 58};
 
int& height(int i) {
    return heights[i];
}
 
int main() {
    height(1) = 44; // person 1 grew!  Is this legal?
}

Questions

  1. In what contexts is heights an l-val, and in which is it an r-val?
  2. What does the ampersand mean in this program?

Model 3: Conditionals

1
2
3
4
5
6
7
8
9
int main() {
    int x = 5;
     
    if(x < 10) {
        x = x + 1;
    } else {
        x = x - 1;
    }
}

Questions

  1. Rewrite this code using only GOTO statements for the body of the if and else clauses, like in BASIC.
  2. Which structure do you prefer and why?

Model 4: Iteration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Driver {
    public static void main(String[] args) {
        ArrayList<String> people = new ArrayList<String>();
         
        // populate with Strings...
         
        Iterator i = people.iterator();
         
        while(i.hasNext()) {
            String person = i.next();
            System.out.println(person);
        }
    }
}

Questions

  1. Re-write this loop with a traditional counter loop. How might this work using GOTO structures?

Model 5: Functions and Evaluation Strategies

1
2
3
4
5
6
7
8
9
10
int main() {
    // suppose this returns some pointer that might be NULL
    // and that ListNode is a traditional linked list node
    struct ListNode* ptr = getHead();
     
    // Suppose getNext(ListNode* x) returns x->next
    if(ptr != NULL && getNext(ptr) == NULL) {
        printf("I am the only elment in this list!\n");
    }
}

Questions

  1. In C, what would happen if ptr is NULL? Would this program fail?
  2. From context, what do you think lazy evaluation means?
  3. Would this outcome be different in an eager evaluation language?

Model 6: Generator Functions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# explicitly write a generator function
def double(L):
    for x in L:
        yield x*2
 
# eggs will be a generator
eggs = double([1, 2, 3, 4, 5])
 
# the above is equivalent to ("generator comprehension"?)
eggs = (x*2 for x in [1, 2, 3, 4, 5])
 
# need to do this if you need a list
eggs = list(double([1, 2, 3, 4, 5]))
 
# the above is equivalent to (list comprehension)
eggs = [x*2 for x in [1, 2, 3, 4, 5]]

Questions

  1. What, in your own words, does a generator do?

Model 7: Recursive Functions

1
2
3
4
5
6
7
8
9
10
; https://www.cs.trinity.edu/~jhowland/ccsc98/ccsc98/node5.html
; scheme < fact.scm
 
(define factorial
  (lambda(n)
    (if (= n 0)
      1
      (* n (factorial (- n 1))))))
       
(factorial 5)       

Questions

  1. What do you think is meant by tail recursion?
  2. Define a recursive approach to find the last item in a list in Scheme. Note that (if (null? (cdr l)) asks if the cdr of list l is null.
  3. Is each call to factorial distinct? In other words, what is each value of n in each function call? Based on this, what do you think is the difference between pass-by-reference and pass-by-value in a function call?

Model 8: Lazy and Eager Evaluation

1
2
3
4
5
6
(define (fibonacci n)
    (if (<= n 2)
        1
        (+ (fibonacci (- n 1)) (fibonacci (- n 2)))
    )
)

Questions

  1. How many times is fibonacci(2) called if the initial call was to fibonacci(3)?
  2. How many times does fibonacci(2) really need to be called? What could we do to help ensure that this happens?

Model 9: Old Fashioned Exceptions

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
#include <stdlib.h>
 
int main() {
    int* x = (int*) malloc(10000000000000*sizeof(int));
     
    if(x == NULL) {
        perror("malloc");
        printf("%d\n", errno);
    }
     
    // printf("%d\n", 5 / 0); // what would happen?
}

Questions

  1. What is the value of x if malloc fails?
  2. What do you think perror does?
  3. What is errno?
  4. What would happen if a second syscall fails before checking the value of errno? Based on this, what can you say about the variable errno?
  5. In what ways can the read syscall fail?
  6. What would happen if you divided by 0 in C?

Model 10: Explicit Exception Handling

1
2
3
4
5
6
7
8
try:
    foo()
catch SomeError:
    print("SomeError occurred")
catch SomeOtherError:
    print("SomeOtherError occurred")
catch:
    print("Any other type of error occurred")

Questions

  1. How might you use this structure to recover and proceed when an exception occurs?
  2. What might you do if you encounter an exception from which you cannot recover?

Model 11: Throwing Exceptions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Driver {
    public double doSomething(int x) throws Exception {
        if(x == 0) {
            throw new Exception("Can't divide by 0!");
        }
         
        return 10.0 / x;
    }
     
    public static void main(String[] args) {
        try {
            System.out.println(doSomething(0));
        catch(Exception e) {
            Sytstem.out.println(e.getMessage());
            e.printStackTrace();
        }
    }
}

Questions

  1. How can this approach be used to enforce preconditions?

Model 12: Garbage Collection

1
2
3
4
5
6
7
8
9
10
11
public class Driver {
    public double doSomething(int x) {
        ArrayList<String> x = new ArrayList<String>();
         
        // work with x
    }
     
    public static void main(String[] args) {
        doSomething();
    }
}

Questions

  1. When is x discarded?
  2. How does this differ from C++?
  3. What are some strategies for determining when it is safe to garbage collect a variable?

Submission

Submit your answers to the questions using the Class Activity Questions discussion board. You may also respond to questions or comments made by others, or ask follow-up questions there. Answer any reflective prompt questions in the Reflective Journal section of your OneNote Classroom personal section.