{"id":"recursion-going-wrong","slug":"when-it-goes-wrong","title":"When recursion goes wrong","text":"A recursive method needs a base case, and every call must get closer to it. When one of the two is missing, the calls never stop, and the program crashes.\n\n### No base case\n\nHere is `digits` from step 2 with its base case left out. A program that crashes this way prints a very long report, so this one catches the error (module 42) and prints one line instead:\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        try {\n            System.out.println(digits(4096));\n        } catch (StackOverflowError e) {\n            System.out.println(\"The calls never stopped: \" + e);\n        }\n    }\n\n    public static int digits(int n) {\n        return 1 + digits(n / 10);\n    }\n}\n```\n\n```output\nThe calls never stopped: java.lang.StackOverflowError\n```\n\n`digits(4096)` calls `digits(409)`, `digits(40)`, `digits(4)` and `digits(0)`, and then `digits(0)` again and again, since `0 / 10` is 0. None of the calls ever returns. Every call of a method takes some memory on the call stack for its parameters and variables, and gives it back when it returns. The call stack has a fixed size, so a chain of calls that never returns fills it up. Java then throws a **StackOverflowError**. It's an error, not an exception (its class extends `Error`, not `Exception`): errors are for problems a program usually can't recover from, and catching one is rare. It's done here only to keep the page short.\n\nWithout the `try` (with `System.out.println(digits(4096));` alone in `main`), the program would crash with a report like this, where line 7 is the line of the recursive call:\n\n```text\nException in thread \"main\" java.lang.StackOverflowError\n\tat Main.digits(Main.java:7)\n\tat Main.digits(Main.java:7)\n\tat Main.digits(Main.java:7)\n```\n\nand so on: the reference JDK prints 1,024 `at` lines, all of them the same. The report lists the calls that were on the stack, newest first, and a report whose `at` lines repeat one method is the sign of a recursion that doesn't stop.\n\nThe fix is the base case that was left out: a number below 10 has one digit, and the method returns 1 without calling itself.\n\n### A base case that's never reached\n\nThe quiz show's `countDown` from step 1 has a base case, `seconds == 0`:\n\n```java\npublic static void countDown(int seconds) {\n    if (seconds == 0) {\n        return;\n    }\n    System.out.println(seconds);\n    countDown(seconds - 1);\n}\n```\n\n`countDown(3)` prints 3, 2 and 1, and stops. But `countDown(-3)` prints -3, -4, -5... and never reaches 0, so it overflows the stack too. (On the reference JDK it prints thousands of lines first. Java Arena stops a program once it has printed 64 KB, so here a program like this is stopped for printing too much before the stack runs out.) The base case exists, but some inputs miss it. A base case written as a range, `seconds <= 0`, catches every input at or past the end. So when you write a recursive method, try it on the smallest inputs: 0, 1, a negative number, and odd and even numbers when the method takes steps of 2.\n\n### Calls that repeat work\n\nA method can also call itself correctly and still be far too slow. A child climbs a staircase one or two steps at a time. In how many ways can they climb `n` steps? The first move is one step (then `n - 1` steps are left) or two steps (then `n - 2` are left), so the ways for `n` are the ways for `n - 1` plus the ways for `n - 2`. 0 or 1 steps can be climbed in one way. These are the Fibonacci numbers.\n\n```java\npublic class Main {\n    public static void main(String[] args) {\n        System.out.println(ways(4));\n        System.out.println(ways(30));\n    }\n\n    public static long ways(int steps) {\n        if (steps <= 1) {\n            return 1;\n        }\n        return ways(steps - 1) + ways(steps - 2);\n    }\n}\n```\n\n```output\n5\n1346269\n```\n\nThe answer is right, but each call makes two more, and they repeat the same work: `ways(30)` calls `ways(29)` and `ways(28)`, and `ways(29)` calls `ways(28)` again. The number of calls grows about as fast as the answer itself; for `ways(30)`, it's over two million, and every 10 more steps make it more than a hundred times larger. A loop that adds up the ways from the bottom (or a recursive method that remembers its answers in a HashMap) does about one round per step. The third challenge of this step counts the calls.\n","task":"A ball is dropped from a height in centimeters, and each bounce reaches half the height of the one before, in whole centimeters (`/ 2` on an int). From 40 it reaches 40, 20, 10, 5, 2 and 1, and then it lies still. `heights(height)` should return how many of those heights are above 0, the first drop included: 6 for 40. The method below has no base case: after 1 it calls `heights(0)`, and `heights(0)` calls `heights(0)` again and again (`0 / 2` is 0), until the StackOverflowError. Add a base case: for a height of 0 there is nothing left to count, so it returns 0 without calling itself. Keep the method recursive. The check runs `System.out.println(heights(40));` and expects:\n\n```\n6\n```\n","kind":"code","seed":"public class Main {\n    public static void main(String[] args) {\n        System.out.println(heights(40));\n    }\n\n    public static int heights(int height) {\n        return 1 + heights(height / 2);\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        System.out.println(heights(40));\n    }\n\n    public static int heights(int height) {\n        if (height == 0) {\n            return 0;\n        }\n        return 1 + heights(height / 2);\n    }\n}\n","hints":["The base case goes at the start of the method, before the recursive call.","`if (height == 0) { return 0; }` stops the calls when the ball doesn't bounce any more: from 1, the call `heights(0)` then adds nothing, and `heights(1)` returns 1 + 0."],"tests":[{"name":"System.out.println(heights(40));","stdin":"","call":"System.out.println(heights(40));\n","expect":"6","hidden":false},{"name":"Test 2","stdin":"","call":"System.out.println(heights(1));\nSystem.out.println(heights(0));\nSystem.out.println(heights(1000));\n","expect":"1\n0\n10","hidden":true}],"require":[{"pattern":"\\bheights\\s*\\(","min":3,"message":"Keep `heights` recursive: it should still call itself."}],"forbid":[{"pattern":"\\b(for|while)\\b","message":"Fix it with a base case, without a loop."}],"more":[{"task":"A staircase is climbed two steps at a time; when one step is left, the last move is a single step. `moves(steps)` should return how many moves the climb takes: 3 for 6 steps, 3 for 5 steps (2 + 2 + 1), and 0 for 0 steps or fewer. The method below works for even numbers, but an odd number jumps over its base case, and so does a negative one, and the program crashes with a StackOverflowError. Fix the base case so that every input reaches it. Keep the method recursive. The check runs:\n\n```java\nSystem.out.println(moves(6));\nSystem.out.println(moves(5));\nSystem.out.println(moves(-4));\n```\n\nand expects:\n\n```\n3\n3\n0\n```\n","kind":"code","seed":"public class Main {\n    public static void main(String[] args) {\n        System.out.println(moves(6));\n        System.out.println(moves(5));\n        System.out.println(moves(-4));\n    }\n\n    public static int moves(int steps) {\n        if (steps == 0) {\n            return 0;\n        }\n        return 1 + moves(steps - 2);\n    }\n}\n","solution":"public class Main {\n    public static void main(String[] args) {\n        System.out.println(moves(6));\n        System.out.println(moves(5));\n        System.out.println(moves(-4));\n    }\n\n    public static int moves(int steps) {\n        if (steps <= 0) {\n            return 0;\n        }\n        return 1 + moves(steps - 2);\n    }\n}\n","hints":["`moves(5)` calls `moves(3)`, `moves(1)` and then `moves(-1)`, which isn't 0. Which numbers should count as \"no steps left\"?","Make the base case a range: `if (steps <= 0)`. `moves(1)` then returns 1 + `moves(-1)`, which is 1 + 0: the last single step."],"tests":[{"name":"Test 1","stdin":"","call":"System.out.println(moves(6));\nSystem.out.println(moves(5));\nSystem.out.println(moves(-4));\n","expect":"3\n3\n0","hidden":false},{"name":"Test 2","stdin":"","call":"System.out.println(moves(0));\nSystem.out.println(moves(1));\nSystem.out.println(moves(2));\nSystem.out.println(moves(-1));\nSystem.out.println(moves(999));\n","expect":"0\n1\n1\n0\n500","hidden":true}],"require":[{"pattern":"\\bmoves\\s*\\(","min":5,"message":"Keep `moves` recursive: it should still call itself."}],"forbid":[{"pattern":"\\b(for|while)\\b","message":"Fix the base case, without a loop."}]},{"task":"How much work does `ways` repeat? The program reads a number of steps, `n`, and prints the number of ways to climb them (the method of this step), then how many times `ways` was called in all, the first call included. Count the calls in a variable that `ways` adds one to each time it starts. A variable declared inside `ways` won't do, since each call gets its own. Declare it in the class, outside the methods, with `static`: `private static long calls = 0;`. A static variable belongs to the class itself, not to an object or a call, so every call of `ways` and `main` see the same one.\n\nFor 4 steps, `ways(4)` calls `ways(3)` and `ways(2)`; `ways(3)` calls `ways(2)` and `ways(1)`; each `ways(2)` calls `ways(1)` and `ways(0)`. That's 9 calls. With the input `20`, the program prints:\n\n```\nWays: 10946\nCalls: 21891\n```\n","kind":"code","seed":"import java.util.Scanner;\n\npublic class Main {\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        int n = Integer.valueOf(scanner.nextLine());\n        System.out.println(\"Ways: \" + ways(n));\n    }\n\n    public static long ways(int steps) {\n        if (steps <= 1) {\n            return 1;\n        }\n        return ways(steps - 1) + ways(steps - 2);\n    }\n}\n","solution":"import java.util.Scanner;\n\npublic class Main {\n    private static long calls = 0;\n\n    public static void main(String[] args) {\n        Scanner scanner = new Scanner(System.in);\n        int n = Integer.valueOf(scanner.nextLine());\n        System.out.println(\"Ways: \" + ways(n));\n        System.out.println(\"Calls: \" + calls);\n    }\n\n    public static long ways(int steps) {\n        calls++;\n        if (steps <= 1) {\n            return 1;\n        }\n        return ways(steps - 1) + ways(steps - 2);\n    }\n}\n","hints":["Declare the counter in the class, outside the methods: `private static long calls = 0;`. Make `ways` add one to it as its first line, before the base case, so that every call is counted.","Print the count after the line that prints the ways: the calls are counted while `ways(n)` runs."],"tests":[{"name":"Test 1","stdin":"20\n","expect":"Ways: 10946\nCalls: 21891","hidden":false},{"name":"Test 2","stdin":"4\n","expect":"Ways: 5\nCalls: 9","hidden":true},{"name":"Test 3","stdin":"1\n","expect":"Ways: 1\nCalls: 1","hidden":true},{"name":"Test 4","stdin":"25\n","expect":"Ways: 121393\nCalls: 242785","hidden":true}],"require":[{"pattern":"\\bstatic\\s+(int|long)\\s+calls\\b","message":"Count with a static variable `calls`, declared in the class outside the methods."},{"pattern":"\\bways\\s*\\(","min":4,"message":"Keep `ways` recursive, as it is."}],"forbid":[]}]}