# 11: End-of-Project-1 Review (Java, Patterns, Testing, etc.) ###### tags: `Tag(sp22)` ## Reading The Notes After Lecture? I never said what "PECS" stands for! It stands for... * Producer: `extends`. * Consumer: `super`. ## Logistics and Preview * Based on hours discussions and feedback, we're rearranging Sprint 3 (which will still be released later this week). Highlights: * React will be in Sprint 4, not Sprint 3. * ...so I won't be talking about React today. * We'll push the React lab to next week. * There will be no lab this week. * **Class next Thursday: Emmanuel Schanzer guest lecture**! Don't miss it if you're able to attend. **Show our hospitality: don't miss Emmanuel's talk, and ask him questions!** * I'm holding an extra OO/Java recitation section tomorrow (Wednesday) at 1pm, in my [Zoom](https://cs.brown.edu/~tbn/zoom.txt). Today will be several cross-cutting exercises and discussions that will be useful, either for general (debugging!) or specific Sprint 2 (generics) reasons. I've tried to address various questions I've gotten but haven't been able to discuss in class. ## Investigating Bugs: JavaScript There was a coda to last Thursday's lecture notes involving a puzzling behavior at the JavaScript console. I want to run through it, because it demonstrates how subtle debugging can be. (If you have read the notes and recall the example, don't spoil it for others!) ### Debugging In The Console Many functions you call in JavaScript are asynchronous. There are also some behaviors that can look asynchronous but are tangled with other issues. Here's a great example that we can run in the browser console: ```javascript var arr = [0,1,2] for(var i = 0; i<arr.length;i++) { arr[i] = -1; console.log(arr); }; ``` Here's the output in the console: ``` Array(3) [ -1, 1, 2 ] Array(3) [ -1, -1, 2 ] Array(3) [ -1, -1, -1 ] ``` But if I click the arrow to expand the first array: ``` Array(3) [ -1, 1, 2 ] 0: -1 1: -1 2: -1 length: 3 <prototype>: Array [] ``` What's going on here? It looks like concurrency could be involved, because we see an apparent delay in the effect of the `for` loop's assignment statements. <details> <summary>Think, then click!</summary> This behavior isn't about whether a call is asynchronous. Rather, it's about how the *console itself* works. When we print out an object with `console.log`, it prints the object summary, but gives us the option of "clicking in" for more details. How does the console do this? It wouldn't be efficient to pre-expand the object and store a string---instead, it probably stores a reference to the object. That's why expanding the array shows different values than the summary. This apparent "delay" isn't about concurrency at all; it's about how the browser console is implemented. </details> ### Confirming The Hypothesis Suppose we add a little bit more: ```javascript var arr = [0,1,2] for(var i = 0; i<arr.length;i++) { arr[i] = -1; console.log(arr); }; arr = [0, 0, 0]; console.log(arr); for(var i = 0; i<arr.length;i++) { arr[i] = 10; console.log(arr); }; ``` If our hypothesis above were correct, what would we expect to see? <details> <summary>Think (and experiment!) then click!</summary> When we re-assign `arr` to a _new_ array, the second `for` loop is modifying that array, not the old one. So there are now two distinct references that the console keeps. We'd like the first 3 console entries to expand to show `-1` but the 4 later entries to all show `10`. </details> **Takeaway:** If you're dealing with a subtle bug that you can't understand by itself, make small changes locally to make sure you understand what's really going on. **This principle applies in _any_ programming language.** ## Back to Java: `static` The `static` keyword in Java has (at least) 4 different contexts. They all relate to whether data, or computation, are associated with a _class_ or with an _object_. ### Static Fields ```java class ThingCounter { private static long counterForClass = 0; private long counterForObject = 0; void increment() { counterForObject++; counterForClass++; } public long counter() { return counterForObject; } public long allCounter() { return counterForClass; } } class CounterDemo { public static void main(String[] args) { ThingCounter c1 = new ThingCounter(); ThingCounter c2 = new ThingCounter(); c1.increment(); c2.increment(); System.out.println(c1.counter()); System.out.println(c2.counter()); System.out.println(c1.allCounter()); System.out.println(c2.allCounter()); } } ``` Static fields are useful if you want to have some canonical value or reference shared by all instances of a class. ### Static Code Blocks If you want to write code that executes as part of the initialization of a _class_, you can add a static block: ```java public class StaticBlockDemo { static { System.out.println("Class is loading (executes only once)..."); } public static void main(String[] args) { System.out.println("Main is invoked..."); } } ``` You won't see static blocks often. When you do, it may be related to loading external native-code libraries, or setting up special classes that should only ever be instantiated once. You can also use it to ensure assignment of `final static` fields in a class. ### Static Methods A static method in Java belongs to the class, rather than to an instance of the class. You see this most commonly in the `main` method, which is an entry point into the program. If I instantiate the class that contains the `main` method, there is still only one `main` method to call. ```java public class Main { public static void hi() { System.out.println("hi"); } public static void main(String[] args) { Main m1 = new Main(); Main m2 = new Main(); hi(); Main.hi(); m1.hi(); m2.hi(); } } ``` All 4 calls here work, and refer to the same `hi` method. IntelliJ warns us that the last 2 calls are suspicious: ``` Static member 'edu.brown.cs32.livecode.mar08.Main.hi()' accessed via instance reference ``` Static methods are often used to build factories, which separate out the creation of a class from that class itself (e.g. `Collections.unmodifiableMap`) or utility methods that work with a class without being defined within it (e.g., `Arrays.toString`). ### Static Member Classes Finally, you'll sometimes see the `static` keyword used on _classes_. You can only apply it to a _member_ class (a class defined within another class, also sometimes called a _nested_ class). It means that the member class cannot refer to members of its enclosing class. E.g., this gives an error: ```java public class StaticClassDemo { int value = 0; static class Inner { value++; } } ``` You can read more about the static keyword and static classes in Effective Java. **Non**-static member classes are often good for implementing the adapter pattern (e.g., iterators). **Static** member classes are good for class-internal data storage that doesn't require access to the enclosing class instance (e.g., the node objects in a tree data structure). ## Break! This is a good time for a break. ## A Generics Exercise Which of these 4 commented-out statements will have an error? ```java public class GenericsExercise1 { public static void main(String[] args) { Collection<Number> someNums = new HashSet<>(); someNums.add(1); // setup (works) someNums.add(1.5); // setup (works) someNums.add(null); // setup (works) // Bounded wildcard: any subtype of Number Collection<? extends Number> someNums2 = new HashSet<>(); // Which of these will be OK? //someNums2.add(1); // ? //someNums2.add(1.5); // ? //someNums2.add(null); // ? //someNums2 = someNums; // ? System.out.println(someNums2); } } ``` <details> <summary>Think, then click!</summary> The first two (adding `1` and adding `1.5`) both give an error. The second two (adding `null` and assigning the reference in `someNums` to `someNums2` don't produce an error). </details> **Why do you think this is?** <details> <summary>Think, then click!</summary> The trick is that a generic type variable, whether a wildcard or something with a name, like `T`, corresponds to _one type_. The bounded wildcard `? extends Number` means "some single subtype of `Number`", and so a collection of `? extends Number` _is not_ a collection of _different_ kinds of `Number`. It's a collection of some single specific type of `Number`. The compiler doesn't know what kind of `Number` the collection contains, and so we can't add either of those subtypes of `Number`. In contrast, we can _extract_ elements of `someNums2` as `Number`s: ``` for(Number n : someNums2) System.out.println(n); ``` Why does `null` work? After all, `null instanceof Number` evaluates to `false`. It works for the same reason you can say `Number n = null;` in Java: a `null` has no runtime class, but at compile time it only represents the absence of data. </details> ## Another Generics Exercise First, I want to show you that generic type variables can indeed be introduced for a single method, using this syntax: ```java public static <T extends Comparable<T>> void filterLowerThan(Collection<T> a, T value) { a.removeIf(b -> b.compareTo(value) < 0); } ``` The `<T extends Comparable<T>>` is not a return type (that's `void`), but an introduction of the bounded type variable `T`. Now let's try an exercise: ```java class Stack<E> { List<E> actual = new ArrayList<>(); public void push(E element) { actual.add(0, element); } public E pop() { E element = actual.get(0); actual.remove(0); return element; } // What's wrong with this method's type? public void pushAll(Set<E> elements) { for(E e : elements) push(e); } // What's wrong with this method's type? public void popAll(Collection<E> destination) { for(E e : actual) { destination.add(e); } } } ``` What's wrong here? (There are no compiler errors.) <details> <summary>Think, then click!</summary> Similarly to other generics exercises we've run, let's try something like this: ```java public static void main(String[] args) { Set<Number> nums = new HashSet<>(); Set<Integer> ints = new HashSet<>(); Stack<Number> stack = new Stack<>(); stack.pushAll(nums); stack.pushAll(ints); stack.popAll(nums); stack.popAll(ints); } ``` </details> </br> Ok, but now let's _fix_ the problem. Surely the `main` code above is something we'd like to enable about our stack. A caller will be very unhappy if they need to typecase `Integer`s to `Number`s in order to use our data structure. ### Fixing The Problem: The **PECS** Rule How can we fix the types of those 2 methods? Let's start with `pushAll`. <details> <summary>Think, then click!</summary> For `pushAll`, the problem is that we need to be able take a set `elements` that **produces** elements of some subtype of `E`. So we'll say: ```java public void pushAll(Set<? extends E> elements) { for(E e : elements) push(e); } ``` </details> For `popAll`, will the same fix work? <details> <summary>Think, then click!</summary> No. We don't really want something that **produces** elements of a subtype of `E`. Instead, we want something that can **consume** elements of a subtype of `E`. ```java public void popAll(Collection<? super E> destination) { for(E e : actual) { destination.add(e); } } ``` To see why, suppose our `Stack` stores `Number`s, and follow the chain of logic. </details> </br> I always have to think through `? super E` and remind myself why it's even a thing. We need it here because we need to be certain that it's safe to add an element to the consumer class. This is only true if its type parameter is an *ancestor* of `E`! E.g., we can plug any kind of `Number` into (e.g.) an Object, but not into (e.g.) an Integer. ## Potential Future Topics Include Future topics: * dynamic vs. static dispatch * microbenchmarking and profiling * reviewing how to use dependency injection with the REPL * dangers: handling memory in your cache * ...