Challenge

Mutate or reassign

20 minjunior06 yrs

Edge cases. You have to reason, and two valid fixes differ.

What this teaches

  • Following the reference is visible to the caller; moving it is not
  • The same parameter type gives opposite outcomes depending on one line
  • Setting a parameter to null does nothing at all
  • Immutable arguments remove the ambiguity entirely

Starter

Starter.java
import java.util.*;

/**
 * Challenge: six methods, one parameter type, opposite outcomes.
 *
 * Predict every line of output before you run this. Write your predictions
 * down — being wrong on paper once is the point.
 *
 * For each method, ask exactly one question: does the body FOLLOW the arrow, or
 * MOVE the arrow?
 */
public class Starter {

    static void a(List<String> list) {
        list.add("a");
    }

    static void b(List<String> list) {
        list = new ArrayList<>();
        list.add("b");
    }

    static void c(List<String> list) {
        list.add("c1");
        list = new ArrayList<>();
        list.add("c2");
    }

    static void d(List<String> list) {
        list = null;
    }

    static void e(List<String> list) {
        list.clear();
    }

    static void f(StringBuilder sb) {
        sb.append("!");
        sb = new StringBuilder("ignored");
        sb.append("?");
    }

    public static void main(String[] args) {
        List<String> l1 = new ArrayList<>();
        a(l1);
        System.out.println("a -> " + l1);

        List<String> l2 = new ArrayList<>();
        b(l2);
        System.out.println("b -> " + l2);

        List<String> l3 = new ArrayList<>();
        c(l3);
        System.out.println("c -> " + l3);

        List<String> l4 = new ArrayList<>(List.of("survivor"));
        d(l4);
        System.out.println("d -> " + l4 + "  size=" + l4.size());

        List<String> l5 = new ArrayList<>(List.of("x", "y"));
        e(l5);
        System.out.println("e -> " + l5);

        StringBuilder sb = new StringBuilder("start");
        f(sb);
        System.out.println("f -> " + sb);

        // TODO 1: for each of a-f, write a one-word note: "follows" or "moves".
        // Method c and f each do both — say which statement did what.

        // TODO 2: state the rule in one sentence, WITHOUT using the word
        // "reference" more than once. If you cannot, you do not have it yet.

        // TODO 3: write a method that takes a list and genuinely cannot modify
        // the caller's list — enforced by the code, not by a comment.
        //
        //     static int countLongNames(??? names)
        //
        // Then explain what happens if a caller passes a mutable list to it
        // anyway, and whether the ELEMENTS are protected too.
    }
}

Run it locally:

cd exercises/java/oop/pass-by-value/02-challenge
javac Starter.java -d /tmp/out && java -cp /tmp/out Starter

Hints

  1. Hint 1

    For each method ask one question: does this line follow the arrow, or move the arrow? Only the first is visible outside.

  2. Hint 2

    sb.append(...) follows it. sb = ... moves it. There is no third case.

  3. Hint 3

    null is just another value to assign to the parameter.

  4. Hint 4

    For the last task, think about what the caller can still do to the object after handing it over — and how to take that ability away.

Done when

  • You predicted all six outputs before running, and can explain each
  • You can state the rule in one sentence without using the word reference twice
  • The final method cannot modify the caller's list, enforced by the types

← Back to Is Java pass-by-value or pass-by-reference?