Swan's Guide to Being a Level 1 Computer

Why?

Because if you want to be good at bossing around computers, you must become one with the computer.

If you ever wanted a beginner's guide to programming that looks down on you (for not having enough fingers), HERE IT IS!

What?

If I, in the real world, handed you a bunch of pieces of paper, each with a number written on it, and asked you to sort them, you could!

If I tell you to write code to do that, it's an entirely different problem.

The goal of this guide is to let you think about programming in the real-world, and then show you how to turn your real world actions into code. This is done by having you pretend to be a computer, in the real world.

HERE BE DRAGONS

Programming is different from other subjects you have studied. You will not write a perfect program on your first try. Or on your second try. If you are wildly talented, you may get it on your fifth try.

This is not because you are bad at computers. I have a bachelor's degree in computer science, I work as a programmer, and I have several years of experience. I very rarely get things right on my first try.

Here is a demonstration of some volunteers attempting to make a sandwich, as computers: (this is a link) This is Harvard. Their students aren't stupid, but as the professor says, when it comes time ... to instruct a computer to do something, you'll be surprised just how often and how bad you are at that, when you're doing this, most likely, for the very first time.

In real life, even in a programming job, nobody is going to put a gun to your head and demand you write perfect code on the first try or else. That just doesn't happen, and there's no reason it would. You will always be able to try things, make a bunch of mistakes, fix problems, and eventually get it right. (Except oddly in computer science tests and interviews, but bad tests are a different problem).

Being good at computers is much more about being able to eventually make your code work. Your mindset should not be my code didn't work, why am I stupid?. My approach to programming (and you may want to copy it), is to expect my code to be wrong. I create working code by trying it again and again, seeing what goes wrong, and fixing that problem.

As a warning, once you get past beginner level programming, you will need to learn more about these concepts. This guide simplifies things to be most useful for beginners, and at most a reference for people past that.

This is not a replacement for lessons. This will ignore many dark corners of Java and programming. It is very likely you will be tested on these dark corners. So take notes from other sources too, this alone is not enough.

Doing Anything At All

I expect that someone or something else will teach you a little about the basics of Java. What it is, how to run Java code, etc. This is a supplement to their lessons, not a replacement.

I expect you to write your code in a file called MyCode.java, it should at least have:

public class MyCode {
public static void main(String[] args) {
System.out.println("Hello, World!");
// code goes here
}
}

I Need to Add Big Numbers But Only Have 10 Fingers

First off, let's not do more than we have to. You also have 10 toes. Which means you've got 20 fingers and toes in total. Is that enough?

Fine. We'll do it with computers.

int 私 = 23;
int 気 = 37;
int 全 = 私 + 気;
System.out.println(全);

When you run this, the computer will say 60.

Why Are Those Names Weird?

This is your first lesson in being a computer. It doesn't matter what you name your variables. To the computer, they all look weird. Computers cannot read English. The computer does not care what you call your variables. (You can't actually use kanji in Java, this is just for example purposes).

Ok, So How Does That Work

Now, we pretend you are the computer. People might have told you computers are smart. They're wrong. Computers are literally as dumb as a rock. Your computer is made of fancy rocks, so obviously it is no smarter than rocks. The fact that we can make computers do anything is a minor miracle. Fortunately a lot of people have done very clever things, so that computers are slightly more useful than mere piles of rocks.

So as a real world computer, this first line (int 私 = 23;), means that you have a piece of paper labelled . That piece of paper has the number 23 written on it. Similarly the second line, int 気 = 37; means you have a piece of paper labelled , with 37 written on it.

The third line is more interesting. You might already guess that you will end up having a piece of paper labelled . However, it will not have 私 + 気 written on it.

This is your first piece of work as a computer. You have:

Now your current problem is what to write, instead of 私 + 気. You need to find the paper labelled , and replace the in your problem, with whatever is written on the paper labelled .

Now you should have 23 + 気. The same thing is done for ; replace it in your problem, with whatever the right piece of paper has written on it. Now your problem should be 23 + 37.

23 + 37 is pretty direct. Just add them as per request. You may have to stretch your imagination to do this, but just pretend you have 100 fingers on each hand, and three hands; so you can actually add those numbers. (Technically, you could say that modern computers have 8 hands, with 18,446,744,073,709,551,615 fingers on each hand).

Your problem should now have been simplified to 60. You can write that down on the paper labelled .

The final line System.out.println(全);, should be read as two parts. First, System.out.println is telling you, the computer, to say something. Second, (全), is telling you what to say.

Obviously, you, the computer, cannot say . Assuming you only speak English, you don't know what that says, or how to pronounce it. Neither do real computers. Now what you, the computer, are expected to do, is find a piece of paper labelled , and say whatever it has written on it. In this case, the paper says 60. Say 60.

Why Did That Take So Long?

Here's a sneak peek into the life of real computers. That was a vacation from a computer's perspective. Computers are great because these days, they tend to do trillions of things every second.

That's the benefit of learning how to command computers. You can make them do trillions of things per second for you!

Why Did You Keep Putting ;?

Computers are stupid. If you don't tell a computer when you've finished saying something, it gets confused. To a computer, it would look like: int 私 = 23int 気 = 37int 全 = 私 + 気System.out.println(全).

In human terms, it would be like not putting a period at the end of my sentences it starts to get kind of weird you might be able to tell where one sentence stops and the next begins if you pay attention it's worse for computers though, since in languages like Java they can't really make guesses about where one stops and the next starts (The language Javascript tries this... It is one of many reasons why Javascript is a nightmare from the dark abyss)

What's Up With int?

This is because computers are stupid. When I write 60 on a piece of paper and hand it to a computer, all it sees is pencil marks. It doesn't understand that it says 60. So I need to tell it how to read those pencil marks. When I say int, it tells the computer: these pencil marks are a number.

You might wonder why the computer doesn't just assume everything is a number. This is because we don't only use numbers. Some other not int things I might write down are:

Hey, 42.73 is also a Number!

Yes it is! But computers are stupid. For complicated reasons (try looking up IEEE 754!), computers cannot use 42.73 in the same way they can use 60.

If a number has nothing after the decimal, it is an integer. If it has something after the decimal, it is a floating point number. BE CAREFUL WHEN MIXING THEM.

If you have to use them together, you should always convert them all into integers, or all into floating points. If you, as a real human, could erase everything after the decimal, and still do whatever you need to with those numbers, convert everything to integers. Otherwise, convert it all to floating point numbers.

To convert a floating point number to an integer, use: ((int)my_floaty_number)

To convert an integer to a floating point number, use: ((float)my_integral_number)

Why Does That Say float Instead of floating point number

Programmers are lazy. We decided shorter phrases should be used.

What Types of Pieces of Paper Can I Use?

In general, I like to overuse long and double, and then never think about number ranges again. If your numbers go out of range, weird things happen.

I Want to Know If One Number is Bigger than Another, and Still Don't Have Enough Fingers

Clearly you have a severe finger shortage, and should try and fix that.

Until you can find some more fingers, try this:

int a = 37;
int b = 23;
if (a > b) {
System.out.println("a is bigger than b");
}

Were you tired of the not English variable names? I was tired of writing them.

The first two lines should seem familiar. You, as the computer, should know what pieces of paper you need. Then, things get interesting.

If Computers Can't Read English, Why Does that Say if?

Ok, we taught computers a few special words. if is one of those rare words.

When you, as a computer, see if, it should look something like if (...) { ... }. When we taught computers the word if, we taught them that when they see if, then they should work out if whatever is in (...) is true, and if it is they should do whatever is in { ... }. Keep in mind that if whatever is in (...) is not true (i.e. it is false), then they should not do what is in { ... }.

Your first task as a computer, is to work out what (...) works out to. In this example, we have (a > b). Like before, we replace a and b with whatever is written on those papers. You, as the computer, should end up with (23 > 37). So, glorious computer, is 23 > 37? (Hint: yes, it is). Because 23 > 37, we replace 23 > 37 with true.

Now, you, as the computer, have if (true) { ... }. Which means you should do whatever is in { ... }. In this case, you just say a is bigger than b.

What if a Was Not Bigger Than b?

Pretend we had instead said int a = 23;, and int b = 37;. Then, be the computer again. You should eventually reach if (false) { ... }. Since you don't have (true), your job is done!

What if I Wanted to do One Thing if a > b, and Something else if it isn't?

Your next English word as a computer is else! You can write:

if (a > b) {
System.out.println("a is bigger than b");
} else {
System.out.println("a is not bigger than b");
}

You can probably guess that that does exactly what you asked for.

What if I Want to do Some Forced Complicated Example Case?

Fine.

if (...1...) {
...2...
} else if (...3...) {
...4...
} else if (...5...) {
...6...
} else {
...7...
}

You can do else if (...) { ... } as many times as you want.

!?!?!?

Computer time again. As a good computer, you must always do this in order. First, does (...1...) work out to true? If it does, then do ...2..., after which, you are done. Ignore everything else.

You're not ignoring this, so (...1...) must have been false. Work out what (...3...) is. If it is true, do ...4..., and then ignore the rest.

You can follow the pattern for (...5...) and ...6.... However, if all of (...1...), (...3...), and (...5...) turned out to be false, then, and only then, do you do ...7....

I Don't Like the {} Buttons, What are Those Even For?

Computers are stupid. You will find this to be a continuing theme. This is similar to ;. For example, consider this English:

Ignore the second line.
I am an evil line. Look upon my deeds and weep.
I'm pretty okay.

If we removed {} from our code, that English would turn into:
Ignore the second line. I am an evil line. Look upon my deeds and weep. I'm pretty okay.

It's all one line! (I don't know the size of your screen, but if your screen is big enough, that's all one line).

So those {} are a necessity, if only to prevent evil. They let us put little pieces of our code into groups (called blocks). Then, we can tell the computer what to do with certain blocks. For example with, if (...) { ...1... } else { ...2... }, It means, if (...), do block 1, otherwise do block 2.

I Want to Add a Lot of Numbers

You could always try:


int v1 = 1;
int v2 = 2;
int v3 = 3;
...
int v1000 = 1000;
int sum = v1 + v2 + v3 + ... + v1000;

But that would take a long time to write.

This calls for something new! An array. In the real world, instead of having 1000 pieces of paper laying around, you have 1000 pieces of paper in a binder!

So, quick things you can do with your binder, and their code version:

Hold on, Why do We Get Page 3 Using binder[2]?

Something something assembly instructions something something let us do memory access at offsets.

This is looking under the bed of computer science. You may find monsters (they might turn out to be nice dust bunnies).

The nice version is, [ ... ] means to get the page that is ... pages after the first page. The first page is 0 pages after the first page, so we use binder[0]. The second page is 1 page after the first page, so we use binder[1]. The third page is 2 pages after the first page, so we use binder[2]. In general, to get page n, use binder[n - 1].

Always be careful when trying to get a page from your binders. If a binder has 2 pages, and you try and take page 3, you will find yourself reaching into the howling abyss and pulling out an incomprehensible monster that washes your car but eats your tires. Make sure your binder has enough pages, and always think about the possibility that your binder has no pages.

Now, with our binder, we can

int[] binder = { 1, 2, 3, 4, ..., 1000};
int sum = binder[0] + binder[1] + ... + binder[999];

Wait a Second, is that Shorter at All?

Uhhh... Not sure. Fine fine. I suppose since even I didn't bother to write it all out, it might be a bit long.

So right now, we want to do something for each page in the binder. Well you could say we want to do something again and again, in a loop. You probably wouldn't say that, but you could. And I mention it because we're about to discover loops.

BEHOLD

int sum = 0;
int page_number = 1;
while (true) {
if (binder.length + 1 == page_number) {
break;
}
sum += binder[page_number - 1];
page_number += 1;
}

Well I Guess That's Shorter, You Actually Wrote it All Out

It is! I did!

What is this while Thing? Why do You Want Me to break?

Some new English for our poor illiterate computers! I'll even throw in a freebie, 3 for 2! You can have continue free of charge!

When a nice computer like you sees while (...) { ... }, it means you should do the following:

  1. Work out (...)
  2. If it worked out to (true), do { ... }
  3. Go back to the first step
Of course, you may notice that you always go back to the first step. This is inconvenient. Especially since you will eventually run out of pages, and you don't want to have to take nonexistent pages and summon car washing, tire eating, monsters.

And so we get break. Rather than telling you to do destroy anything, it just means: Stop this silly while thing, and go directly to whatever is after { ... }.

continue is a bit of a soft version of break. It means It doesn't matter if you have more to do in { ... }, go back to step 1. So you're still looping, but you cut short that specific iteration of the loop.

Okay, But Can We Really Not Make it Even Shorter?

I must admit it's not the best we can do. The truth is, there are more kinds of loops. Most importantly, the for loop. There are also those like the do loop, but those are truly silly; they don't exist in many computer languages, and I never liked them anyway, so I won't acknowledge them.

In the end though, it's all a scam. It's just Java trying to sell you the same while loop again and again. That is to say, anything you can do in one type of loop, you can do in all the others.

The for loop is shorter for some uses though, and that's why we like it. Let's try experimenting with our code to make it nicer.

Here's the original again.

int sum = 0;
int page_number = 1;
while (true) {
if (binder.length + 1 == page_number) {
break;
}
sum += binder[page_number - 1];
page_number += 1;
}

Now we'll make this a better while loop, and put the condition inside of (...):
int sum = 0;
int page_number = 1;
while (page_number <= binder.length) {
sum += binder[page_number - 1];
page_number += 1;
}

Now, while we like to think in terms of page_number, most programmers think in terms of pages_after_first, so let's use that:
int sum = 0;
int pages_after_first = 0;
while (pages_after_first < binder.length) {
sum += binder[pages_after_first];
pages_after_first += 1;
}

And this is the limit to what our while can nicely do. Let's do the simplest possible switch to a for loop:
int sum = 0;
int pages_after_first = 0;
for (;pages_after_first < binder.length;) {
sum += binder[pages_after_first];
pages_after_first += 1;
}

You may notice that there's pretty much no change! But this is just to show you how similar the loops are. We can do better with a for loop:
int sum = 0;
for (int pages_after_first = 0; pages_after_first < binder.length;) {
sum += binder[pages_after_first];
pages_after_first += 1;
}

I know, I know, that's not actually shorter, I just moved things around. Let's move more things!
int sum = 0;
for (int pages_after_first = 0; pages_after_first < binder.length; pages_after_first += 1) {
sum += binder[pages_after_first];
}

Now, because that pages_after_first is pretty long, we replace it with the traditional i (which stands for index (into the binder)).
int sum = 0;
for (int i = 0; i < binder.length; i += 1) {
sum += binder[i];
}

This is much nicer.

Let's review this for. When we read for (.1. ; .2. ; .3.) { .4. }, it means:

  1. Make a new page according to .1.
  2. If .2. does not work out to true, you are done, go directly to whatever is after { .4. }
  3. do .4.
  4. do .3.
  5. Go back to step 2
The equivalent while loop is: .1.; while (.2.) { .4.; .3. }

How Do I Computer That?

Let's go all the way through an example:

int[] binder = { 4, 7, 12 };
int sum = 0;
for (int i = 0; i < binder.length; i += 1) {
sum += binder[i];
}
System.out.println(sum);

  1. int[] binder = { 4, 7, 12 };: We make a binder, labelled binder, with 3 pages which have 4, 7, and 12 written on them respectively
  2. int sum = 0;: We make a piece of paper labelled sum with 0 written on it
  3. We start the for loop, go back and review what order to do for loop things in if you must
  4. int i = 0;: We make a new page for our for loop, labelled i, with 0 written on it.
  5. We work out i < binder.length;, since i has 0 on it, and binder.length is 3, it works out to true, so we keep going
  6. sum += binder[i];: We get page i, which says 0, so we get the page in binder which is 0 pages after the first page (which is just the first page). This page has 4 written on it. So this turns into sum += 4;. We add 4 to our page labelled sum, which used to say 0, so it will now say 4
  7. i += 1: We change page i from saying 0 to saying 1
  8. We go back to our for loop condition (i < binder.length), since page i says 1, and binder.length is still 3, we continue
  9. sum += binder[i]; becomes sum += binder[1]; becomes sum += 7;, so page sum changes from 4 to 11
  10. i += 1: We change page i from saying 1 to saying 2
  11. Back to our loop condition (i < binder.length), page i now says 2, and binder.length is still 3, we continue
  12. sum += binder[i]; becomes sum += binder[2]; becomes sum += 12;, so page sum changes from 11 to 23
  13. i += 1: We change page i from saying 2 to saying 3
  14. Back to our loop condition (i < binder.length), page i now says 3, and binder.length is still 3, and since 3 == 3, we're done the for loop!
  15. System.out.println(sum);: page sum says 23, so we say 23
Well computered!

I Want to Add Two Lists of Numbers, and See Which List Has a Smaller Sum

You have strange hobbies. But whatever ticks your processor.

The simple answer is:

int[] binder1 = { 4, 7, 12 };
int[] binder2 = { 3, 10, 12, 7 };
int sum1 = 0;
for (int i = 0; i < binder1.length; i += 1) {
sum1 += binder1[i];
}
int sum2 = 0;
for (int i = 0; i < binder2.length; i += 1) {
sum2 += binder2[i];
}
System.out.println(sum1 > sum2);

Why Do I Have to Tell The Computer Twice that the Page i is for int?

Because computers are stu-...

Actually, wait, this one is different. That page you create in ( ... ;, only exists in that for loop. You can't use it after the loop, only inside the loop. Which means our second loop needs to make a new page. Fortunately, our dumb rock already forgot about the old i page, so we can make a new one with the same name instead of getting creative.

Do I Really Have to Write the Same Loop Code Twice

No, you don't, remember, DRY.

(Never water computers) Before you start trying to dry off your hopefully not wet computer, I should mention that DRY stands for Don't Repeat Yourself. In our case, we already wrote a nice loop, and we don't want to have to write it again, as that would be repeating ourselves.

So how do we not repeat ourselves? It'd be nice if we could say, now do that to binder2, but we can't, because computers are... Go on, you say it this time.

To get this idea across to the dumb rock, we have to start by telling the rock about a thing we want to do multiple times. This thing would be called a function.

Think of a function as another friend/computer. You can ask them to do something for you. But since you want them to do something with your pages, you'll need to give them your pages and binders. You'll probably also want them to give you back a page or binder.

In our case, we want to hand our friend a binder, and we want them to give back a page that has the sum of all pages in the binder written on it. In code, that is:

public static int friendly_person(int[] binder) {
...
}
public static void main(String[] args) {
int[] binder = { 4, 7, 12 };
int sum = friendly_person(binder);
System.out.println(sum);
}

Why is There Static!? Why is it Public!?

One day, when you grow up into a big computer, you'll learn about things like classes, objects, instances, etc. For now, I'm not telling~!

Fine, Explain the Rest

int friendly_person(int[] binder) { ... } is what's important. We've already seen this main stuff in our doing anything at all section (it was a function all along, gasp!).

Let's start with friendly_person, if we have more than one friend, we need a way to get help from a specific friend, so they each need their own, unique name.

The int at the start is how we know what our friend will give us back. In this case, our friend will give us back an int type page.

Can't We Just Take Back Whatever Our Friend Gives Back?

You, as a real person, can. You, as a computer, cannot. Why? Because:

  1. Computers
  2. are
  3. stupid
So if your friend gives you something back, you have to tell the computer what type of page your friend gives back. (if your friend gives nothing back, you say they give back void. Seriously. That's not an edgy joke or anything)

Back to the function! We still have (int[] binder). This is how your friend says what types of pages and binders they expect, and what they're going to label them with. In this case, our friend says: I accept a binder of int pages, and I will label that binder binder.

When our friends accept multiple things, we need to give them those things in the same order, as they expect them. Unfortunately, friends cannot return multiple things.

We also have this { ... } attached to our friend. This is just what your friend is going to do with what you give them.

Now, inside of main, we say int sum = friendly_person(binder);. The piece friendly_person(binder), means, give my friend called friendly_person this binder I call binder, and then replace this with what they give back. Then, of course, int sum = ..., is just making a new page called sum, with whatever your friend gave back written on it.

If friendly_person Says They Give Back an int, Why do I have to Say That sum is a Page of Typ-

Shhhhhhhh. Computers are stupid.

Okay okay, so How Does My Friend do this Work for Me?

Alright, let's fill in the dots here:

public static int friendly_person(int[] binder) {
int sum = 0;
for (int i = 0; i < binder.length; ++i) {
sum += binder[i];
}
return sum;
}
public static void main(String[] args) {
int[] binder = { 4, 7, 12 };
int sum = friendly_person(binder);
System.out.println(sum);
}

And would you look at that, there's our nice loop code!

return?

Our friends don't exist until we call for their help. So return means, Return to the dark void from which ye crawled foul creature! Back! Back! *swing fiery torch*. (Are your friends not like that? Just mine? Hmm...)

Now if our friend gave back void, that would be that, we could just say return;. But this friend gives back an int, so we say return sum;, so our friend gives back their page called sum. We can put this return anywhere in a function, but once we return, the friend is gone, they won't do anything after the return.

Why doesn't the Computer Know to Return sum?

Would you expect a rock to know to return sum?

But I'm Going to Put it Into My Page Called sum

I will refer you to an excellent text on this subject, entitled Computers, on the Stupidity of. Also, the computer is very strict about whose pages are whose. You might both have pages called sum, but since they belong to different people, your computer doesn't even consider the possibility of sharing. Who knew computers supported selfishness? Rocks...

Alright, so How do I Sum Two Lists?

Back on track! Simple:

public static int friendly_person(int[] binder) {
int sum = 0;
for (int i = 0; i < binder.length; ++i) {
sum += binder[i];
}
return sum;
}
public static void main(String[] args) {
int[] binder1 = { 4, 7, 12 };
int[] binder2 = { 3, 10, 12, 7 };
int sum1 = friendly_person(binder1);
int sum2 = friendly_person(binder2);
System.out.println(sum1 > sum2);
}

All we've done is put back two binders into main, and then summon our friend twice.

Remember, the dark abyss our friend is returned to when not serving us makes them lose all their memories. When we call our friend a second time, they have no memory of the first time. This is useful as they don't get confused about multiple binders, or let the sums leak into each other. (Do not try to make your friends forget things, no matter how useful) (Also don't shove them in dark voids, or force them to serve you).

Let's computer out the new stuff:

  1. int sum1 = friendly_person(binder1);: Give our friend binder1 and wait
  2. Friend receives our binder1, as binder
  3. Friend starts work: they start at int sum = 0;, we'll skip to the end
  4. Friend reaches return sum;: Friend gives us their page sum, then slinks back into the darkness.
  5. int sum1 = ...: We put the page they just gave back into our page sum1
  6. int sum2 = friendly_person(binder2);: resummon friend, give them binder2, they eventually give us back their new sum page, we put it in our sum2 page
  7. System.out.println(sum1 > sum2);: simplifies to System.out.println(23 > 32);, which simplifies to System.out.println(false);. So we say false

There you go, we've simplified it so we're not repeating ourselves. Well, not as much.

Help! Someone has Stolen All My Loops!

That's horrible! Did you have insurance? Have you called the police? Good, good. Don't call the police.

Well don't worry. This is what friends are for! I shall teach you to profit off of your friends using Recursion.

It is traditional to teach recursion using examples that would be better done with loops. I, of course, am keeping that tradition, so I stole all your loops (and will sell them for profit on the black market as a bonus!).

Now I could teach recursion with an example where it is actually useful, but that tends to require things like trees.

I Know What Trees Are, Just Teach Recursion Properly

You know what trees are? Then tell me, what do trees have to do with computers?

Do You Put Computers in Trees?

This is why I had to steal your loops. In computer science, trees are intricate webs of pages which only kind of resemble Australian trees (upside down trees). And I'm not going to talk about them here.

Let's start with a warning about recursion. Go to the Google search page for recursion. No, I didn't misspell recursion. But click the suggested correction in Did you mean: recursion anyway. And click it again. And again.

It just keeps going. This is the dreaded infinite recursion (anything to do with infinity should be treated with respect, if not dreaded). Rule number one of recursion is: MAKE SURE YOUR RECURSION STOPS.

What Actually is Recursion, and Why Did You Steal My Loops?

As it turns out, recursion is just another loop in disguise (see, I didn't steal all your loops, please call off the police). It's just the silliest of loops, which is probably why it generally isn't allowed at the big loop table.

Let's stick with our add all numbers in a list example. We used to have:

public static int friendly_person(int[] binder) {
int sum = 0;
for (int i = 0; i < binder.length; ++i) {
sum += binder[i];
}
return sum;
}
public static void main(String[] args) {
int[] binder = { 4, 7, 12 };
int sum = friendly_person(binder);
System.out.println(sum);
}

But this uses a for loop, so it isn't allowed.

Now clearly we in the main function have solved the problem, by making it our friend's problem. This is the correct approach.

However, if our friend does the same, and makes it another friend's problem, then it'll never stop. We'll just have infinite friends acting all smug about their problems being someone else's problem.

The key insight, and one of many useful perspectives on recursion, is to turn our problem, into a slightly smaller problem for someone else.

So before handing our problem to friendly_person, let's make it smaller:

public static int friendly_person(int[] binder) {
int sum = 0;
for (int i = 1; i < binder.length; ++i) {
sum += binder[i];
}
return sum;
}
public static void main(String[] args) {
int[] binder = { 4, 7, 12 };
int sum = binder[0];
sum += friendly_person(binder);
System.out.println(sum);
}

The key changes are: Now our friend's problem is indeed slightly smaller. They have to add one less number.

Now, let's have our friend make their problem slightly smaller, and then give it to someone else:

public static int other_friendly_person(int[] binder) {
int sum = 0;
for (int i = 2; i < binder.length; ++i) {
sum += binder[i];
}
return sum;
}
public static int friendly_person(int[] binder) {
int sum = binder[1];
sum += other_friendly_person(binder);
return sum;
}
public static void main(String[] args) {
int[] binder = { 4, 7, 12 };
int sum = binder[0];
sum += friendly_person(binder);
System.out.println(sum);
}

Now our friend also just takes one number, hands off the rest to another friend, and then adds whatever they return, before returning themselves. You should try to computer this one out to confirm that the result is still the same. (I don't know if it is the same, I never tested most of this code. But it is supposed to be the same).

Now of course, this still uses a loop. Fortunately, we only have 3 pages in our binder, so we can fix that:

public static int other_friendly_person(int[] binder) {
int sum = binder[2];
return sum;
}
public static int friendly_person(int[] binder) {
int sum = binder[1];
sum += other_friendly_person(binder);
return sum;
}
public static void main(String[] args) {
int[] binder = { 4, 7, 12 };
int sum = binder[0];
sum += friendly_person(binder);
System.out.println(sum);
}

No loops! Success!

What Would Happen if My Binder Had 4 Pages?

Why ask when you can just computer yourself (or make your computer computer for you), and see what happens?

I'll spoil the results for you though. It doesn't work. It won't include the fourth number in your sum.

Clearly, we stopped too soon. What we need is an infinite line of friends:

public static int friendly_person_∞(int[] binder) {
int sum = binder[∞];
sum += other_friendly_person_∞+1(binder);
return sum;
}
...
public static int friendly_person_3(int[] binder) {
int sum = binder[3];
sum += other_friendly_person_4(binder);
return sum;
}
public static int friendly_person_2(int[] binder) {
int sum = binder[2];
sum += other_friendly_person_3(binder);
return sum;
}
public static int friendly_person_1(int[] binder) {
int sum = binder[1];
sum += other_friendly_person_2(binder);
return sum;
}
public static void main(String[] args) {
int[] binder = { 4, 7, 12, 17 };
int sum = binder[0];
sum += friendly_person_1(binder);
System.out.println(sum);
}

We now have infinite friends. Which is less great than you'd think (you probably just forgot infinite people's birthdays, you monster). The new binder has 4 pages, so friendly_person_4 will try to grab the page 4 pages after the first (the fifth), and find themselves holding, an incomprehensible monster (their tires will never be found, but their car has never been so clean!). We have forgotten rule number one of recursion: MAKE SURE YOUR RECURSION STOPS.

Ok, a minor, yet ultimately fixable disaster. Send off your infinite friends to Hilbert's Hotel, they're full, but fortunately they can still accommodate infinitely many more guests. (Bonus, did you know there are different sizes of infinity?) Anyway, we'll fix up this code so we have infinitely more friends, but this time these new friends know when to stop:

public static int friendly_person_∞(int[] binder) {
if (∞ == binder.length) { return 0; }
int sum = binder[∞];
sum += other_friendly_person_∞+1(binder);
return sum;
}
...
public static int friendly_person_3(int[] binder) {
if (3 == binder.length) { return 0; }
int sum = binder[3];
sum += other_friendly_person_4(binder);
return sum;
}
public static int friendly_person_2(int[] binder) {
if (2 == binder.length) { return 0; }
int sum = binder[2];
sum += other_friendly_person_3(binder);
return sum;
}
public static int friendly_person_1(int[] binder) {
if (1 == binder.length) { return 0; }
int sum = binder[1];
sum += other_friendly_person_2(binder);
return sum;
}
public static void main(String[] args) {
int[] binder = { 4, 7, 12 };
int sum = binder[0];
sum += friendly_person_1(binder);
System.out.println(sum);
}

Better. Better.

These Friends are Hard to Copy and Paste

You think your other friends are better because you can't copy and paste them? Fine. We'll bring these friends closer to par.

public static int friendly_person_∞(int[] binder, int index) {
if (index == binder.length) { return 0; }
int sum = binder[index];
sum += other_friendly_person_∞+1(binder, index + 1);
return sum;
}
...
public static int friendly_person_3(int[] binder, int index) {
if (index == binder.length) { return 0; }
int sum = binder[index];
sum += other_friendly_person_4(binder, index + 1);
return sum;
}
public static int friendly_person_2(int[] binder, int index) {
if (index == binder.length) { return 0; }
int sum = binder[index];
sum += other_friendly_person_3(binder, index + 1);
return sum;
}
public static int friendly_person_1(int[] binder, int index) {
if (index == binder.length) { return 0; }
int sum = binder[index];
sum += other_friendly_person_2(binder, index + 1);
return sum;
}
public static void main(String[] args) {
int[] binder = { 4, 7, 12 };
int sum = binder[0];
sum += friendly_person_1(binder, 1);
System.out.println(sum);
}

There, now each friend tells the next friend their number. You only have to change the names of the friends.

I Don't Have Time To Write Code for Infinitely Many Friends

You're telling me you can't make time for your friends? Good. Friends are important, but ultimately you shouldn't devote all your efforts toward them, always remember to take care of yourself.

Not only is writing infinitely many friends going to take infinitely long, we're also so infinitely far beyond DRY that we make water look dry.

Alright, so right now we have infinite friends, all the exact same, except they have different names. It'd be nice if we could hand the entire problem to our friend without making it smaller ourselves. And more importantly, if only we could go back to one friend, and just have them give themselves the next smaller problem, something like:

public static int friendly_person(int[] binder, int index) {
if (index == binder.length) { return 0; }
int sum = binder[index];
sum += friendly_person(binder, index + 1);
return sum;
}
public static void main(String[] args) {
int[] binder = { 4, 7, 12 };
int sum += friendly_person(binder, 0);
System.out.println(sum);
}

Why Can't We Do That?

I didn't say we couldn't. I said it would be nice. We can! It is nice! We have just accomplished: Recursion.

How Can My Friend Hand Themself a Problem?

Well it works like this. Your friend summons a friend called friendly_person, so they can be given a problem. The dark abyss knows it has already given you the friend called friendly_person. But it isn't willing to give up on this chance to send more people out, so it creates a clone of your friend, and sends them out. Your original friend then hands their problem off to the clone of themselves, and patiently waits for the clone to finish. New clones are created as needed to make sure the problem is solved.

This is another reason to never forget rule number one of recursion: MAKE SURE YOUR RECURSION STOPS. If we forget, the dark abyss gets to make infinite dark clones, and will swiftly conquer the world.

Why is it Called Recursion?

I don't know. Personally, I think it is because when you are cursed with a problem, you just re-curse yourself with a smaller problem.

How Exactly Does This Relate to Loops Again?

We have:

public static int friendly_person(int[] binder, int index) {
if (index == binder.length) { return 0; }
int sum = binder[index];
sum += friendly_person(binder, index + 1);
return sum;
}
public static void main(String[] args) {
int[] binder = { 4, 7, 12 };
int sum += friendly_person(binder, 0);
System.out.println(sum);
}

The loopy version was:
public static int friendly_person(int[] binder) {
int sum = 0;
for (int i = 0; i < binder.length; ++i) {
sum += binder[i];
}
return sum;
}
public static void main(String[] args) {
int[] binder = { 4, 7, 12 };
int sum = friendly_person(binder);
System.out.println(sum);
}

Now, for a neat trick:
public static int loopy_person(int[] binder) {
int sum = 0;
for (.1.; .2.; .3.) {
.4.
}
return sum;
}
public static void main(String[] args) {
int[] binder = { 4, 7, 12 };
int sum = loopy_person(binder);
System.out.println(sum);
}

is the same as:
public static int cursy_person(int[] binder) {
if (!(.2.)) { return 0; }
int sum = .4.;
sum += cursy_person(binder, .3.);
return sum;
}
public static void main(String[] args) {
int[] binder = { 4, 7, 12 };
int sum = cursy_person(binder, .1.);
System.out.println(sum);
}
Although, of course, this doesn't quite work out nicely enough to copy and paste because we have to adjust things to fit. But the general concepts are there.

So:

This doesn't always work. Or, more accurately, it doesn't always work like this. You can always convert back and forth between recursion and a loop, but exactly how you do that might be complicated, or even almost but not quite impossible.

Getting a feel for recursion comes with practice, and reading good examples. The core concept is making the problem slightly smaller, and then handing it off to someone else (probably just a clone of yourself). It will likely help to think of how you could do this in the real world with infinite custom designed friends, and then work out how to simplify infinite friends into infinite clones of the same friend.

One important thing to note, (which you'll need to write a recursive fibonacci function), is that your friends are not limited to summoning just one clone. Recursive fibonacci generally expects each friend to summon two clones, but gives each a different problem. And this concept extends further, there is no limit on the number of clones any one friend can summon at a time.

Can I Have a Quick Reference Guide?

You may need to change some of the names of variables in the following snippets of code. Probably, usually, i. Traditionally we try j next, then k. Alright, let's go!

I Want a Page For:

I Want A Binder For:

type[] name = { ... };, replace type with the type of page you want to put in your binder (e.g. int pages, go in a binder like this: int[] name = { 1, 2, ..., 10 };

As a side note, you can only have one type of page inside each binder. If you want to know why, I invite you to consider the intelligence level of computers.

I Want to Say Something:

System.out.println(something); Replace something with what you want to say, or the name of the page you want to read out loud.

I Want to Do Something if Something, and Otherwise do Something

if (first_possible_true_thing) {
// Code I want to do if the first_possible_true_thing is true
} else if (second_possible_true_thing) {
// Code I want to do if the first_possible_true_thing was false
// but the second_possible_true_thing is true
} else {
// Code I want to do if the first_possible_true_thing was false,
// and the second second_possible_true_thing was false
}
Replace each _possible_true_thing with a true or false statement, like your_age > 42 or money_i_have + money_they_owe_me == money_i_need.

I Want to do Something a Specific Number of Times

// Code here runs *before* you do something a number of times
for (int i = 0; i < my_number; ++i) {
// Code here is what you want to do a number of times
}
// Code here happens *after* you've finished doing something a number of times
Replace my_number with the number of times you want to do whatever, for example, 42. If you expect to be given a page with the number of times to do something written on it, then replace my_number with the name of that page.

I Want to do Something an Unknown Number of Times

// Code here runs *before* you do something a number of times
while (something_is_true) {
if (i_suddenly_realized_i_need_to_stop) { break; }
// Code here is what you want to do a number of times
}
// Code here happens *after* you've finished doing something a number of times
Ideally, you can replace something_is_true with a simple condition like i < 42. If you have a complicated condition that will take a few lines to write out, then you can use it to replace the i_suddenly_realized_i_need_to_stop piece.

Unless you want an infinite loop, you need to use one of the stopping methods. If you cannot use the simple method, then your loop should start with while (true) {. If you don't need to use the complicated method, then you don't need to include that line. If it makes it easier to write some specific code, you can use both at the same time.

I Want to do Something for Each Page in a Binder

// Code here runs *before* you do something a number of times
for (int i = 0; i < binder.length; ++i) {
// The current page in the binder is binder[i]
// Code here is what you want to do a number of times
}
// Code here happens *after* you've finished doing something a number of times
Change binder to whatever the name of the binder is.

I Want a Function/Friend

public static return_type friend_name(accept_type_1 accept_name_1, accept_type_2 accept_name_2) {
// Code here is what your friend should do
return something_of_return_type;
}
Change return_type to the type of whatever your friend gives back. If they give back a binder of int pages, this would be int[]. If your friend gives back nothing, change it to void, and also remove the line that says return.

Change friend_name to a unique name for your friend. Ideally, this name describes what they do, like: double_this_number.

Change (accept_type_1 accept_name_1, accept_type_2 accept_name_2) into a list of what you will give your friend. For each thing you will give your friend, write the type of the thing (e.g. boolean), and then what your friend will call that thing (e.g. i_should_double_this_number). Put a comma between the things your friend accepts. If you won't give your friend anything, this can be empty: (). An example of taking a binder and a page would be: (int[] numbers_to_search, int number_to_find).

In order to actually call on your friend, you need to say:

returned_type gave_back = friend_name(thing_to_give_1, thing_to_give_2);
Here, returned_type should be the same as your friend's return_type. gave_back will be your page, which will hold whatever your friend gives back. friend_name is the name of your friend. thing_to_give... are the things you give your friend, in the same order as your friend expects them.

If your friend gives back nothing, remove returned_type gave_back = .

I Want to Recursively Process a Binder

public static result_type recurser(int[] binder, int index){
if (binder.length == index) { return default_value; }
// Do something with binder[index]
result_type small_result = recurser(binder, index + 1);
// Do something more with small_result
return something;
}
To use it, say result_type result = recurser(binder, 0);. Remember that the order I do things in here isn't strictly required. If you can't figure out how to make your problem fit my example, try playing around with when and how to do things.

I Want to Recursively Do Something

public static result_type recurser(given_type given_name){
if (we_are_finished) { return default_value; }
// Do something here
result_type small_result = recurser(given_name + 1);
// Do something more with small_result
return something;
}
And start it with result_type result = recurser(first_value);.

Again, play around with the ordering and how things are done. You don't need to add 1 to given_name every time, you just need to make sure your problem is getting smaller. Maybe you'll subtract 2, or maybe you'll be passing a lot of things every time and only changing some of them.

You might need to recurse multiple times, e.g. return recurser(given_name - 1) + recurser(given_name - 2);. Or maybe you'll do stranger things than even that.

I Have Some Frequently Asked Questions

It is indeed time for the FAQ, thanks for asking!

Why are Computers so Stupid?

Honestly, it is generous to call computers stupid. Because that makes people believe computers can think at all. They cannot. They are rocks. Rocks are not even qualified to be stupid.

Then How do Computers do Anything?

Well computers compute using the flow of electricity through rocks. We can use specially carved rocks to make this flow do interesting things like, if electricity is flowing in either of these streams, make it flow down this specific stream.

We can combine these simple actions to make progressively more and complicated actions. Eventually, we make the actions complicated enough for assembly. This is a very simple programming language, in some of the main dialects of this language, we only ever have 8 pages (8 collections of streams electricity can flow through), and everything else has to go into a single massive binder. We're also only allowed to do very simple things, we don't have functions, we don't even have variable names. If we want to say Hello, World!, it could take a screen full of assembly language!

We use assembly language to make a simple program which can understand (again, still a rock, rocks cannot understand), more complex and slightly more useful languages like C.

Eventually, we've done enough work that our computer can understand Java.

But Java is actually pretty old. There are newer, cooler, smarter languages out there. Cool new languages like Rust and Go automatically figure out what types most things are, along with a lot of other magic.

Do You Have Any Fun Facts?

I kept referring to functions as friends, but Java actually has a formal concept of some functions which are friendly. This just means those friendly functions get to see and touch the privates of those they're friendly with. Which doesn't mean what you think it does, which is a little too friendly in my opinion. The creators of Java must have been pretty wild.

Pages are also a real and rather advanced concept in computer science, except they're more like the equivalents of whatever magical place we're getting all this paper from.

Do you have any tips for programming in general?

When in doubt, try running your code, and see what happens.

When still in doubt, throw System.out.println everywhere, print everything. Then run your code. You should computer along your code yourself, and check to make sure that the real computer always says what you as the pretend computer think it should. Once you and the real computer say something different, you have found your next problem to solve.

Always remember to KISS

Err... Don't try to kiss your computer. It probably won't notice, the hard shelled stupid rock that it is. KISS stands for: Keep It Simple Stupid Or, in simpler terms, complicated code is the enemy. The holy grail you must seek is code that is:

Also, remember that you won't always know what's written on the pages a computer has. Try computering through your code, but every time you read what's written on a page, ask yourself, what is the worst possible thing that could be written here?

Why Are You so Bad at Title Capitalization?

Because computers are stupid.

No, wait, that's on me...

I blame my computer. It can't deny it's at fault. It's a rock.

These Incomprehensible Monsters that Wash Cars and Eat Tires Are Worrying

Java's actually got it pretty good, if you release monsters it will panic and complain. In the most excellent language C++, it doesn't stop. It doesn't even warn you that monsters have been unleashed. These monsters will find new and exciting ways to ruin your day, your code, and your car. Although traditionally it's monsters are nasal demons.

One of the things that make Rust a cool new language is that it does a lot to protect you from accidental monsters.

Why Doesn't the Code I Copied from Here Work?

I did say I don't expect my code to work. You shouldn't expect my code to work.

Then Why Does the Other Code I Copied from Here Work?

Does it really? I'mma go write this in my journal.

How Many Fingers Do You Have?

I can count to 1,023 on my fingers. 1,048,575 if I include toes, but I'm not sure my toes are quite up to the task. You could say that I have more than enough fingers.

Where Do I Go From Here?

Try a more formal tutorial, which will be more thorough in teaching you concepts.

If you must use Java, try this one

If you can do whatever you want, but don't intend to devote your life to computer science, you should try Python

If you expect computer science to be a big part of your future, you really should start from the very basics and build an incredibly solid foundation. The practical foundation of computer science is how computers work. This course guides you through designing your own computer, and then using it to make Tetris