Source code, and why it is text

What a source file actually is, what an encoding is, and why your editor matters less than you think.

4 min read🧭 Programming Foundations

A source file is text. Not a document, not a project, not a special format — a sequence of characters, exactly like a note to yourself, that happens to follow rules strict enough for a machine to read.

That is worth proving rather than asserting. Here are the first thirty-two bytes of a Java file, printed as characters:

od -c Hello.java — the file as charactersplaintext
0000000    p   u   b   l   i   c       c   l   a   s   s       H   e   l
0000020    l   o       {  \n                   p   u   b   l   i   c

And the same thirty-two bytes as the numbers they actually are:

od -t x1 Hello.java — the same file as numbersplaintext
0000000    70  75  62  6c  69  63  20  63  6c  61  73  73  20  48  65  6c
0000016    6c  6f  20  7b  0a  20  20  20  20  70  75  62  6c  69  63  20

70 is p. 20 is a space. 0a is the newline at the end of the first line, and the four 20s after it are the indentation — which is how you can tell, from the bytes alone, that this file uses spaces rather than a tab. The whole file is 111 bytes, and every one of them is something you could type.

What follows from that

Any editor works. Notepad, vim, IntelliJ — they all write the same bytes. An IDE gives you a great deal (the lesson on it says what), but none of it changes the file. This is why you can read a project on GitHub in a browser, and why a diff is a list of changed lines rather than a mysterious blob.

Whitespace is mostly for you. Java does not care about indentation; it cares about {, } and ;. Indentation exists so that a human can see the structure at a glance. Languages that do care (Python is the famous one) made a different trade, and both camps are firmly convinced.

The file is not the program. It is a description of one. Turning it into something that runs takes another step, which the next lesson is about.

Encoding: the bit that bites

If a file is characters, something has to decide which bytes mean which characters. That mapping is an encoding, and there is more than one.

Type café in a modern editor and it is saved as UTF-8. Five bytes for four characters:

plaintext
bytes      : 63 61 66 c3 a9
as UTF-8   : café
as Latin-1 : café
lengths    : utf-8 -> 4 chars, latin-1 -> 5 chars

c, a and f are one byte each. é is the pair c3 a9. Nothing in the file records which encoding was meant — the bytes are identical either way — so a program that assumes Latin-1 reads that pair as two separate characters and prints café.

Look at the last line, because it is the part that turns a display annoyance into a bug: the same file is four characters long or five, depending on who is reading it. A length check, a database column of VARCHAR(4), a substring, a truncation for a UI — all of them now disagree about the same data.

This is not a beginner's problem you outgrow. It is one of the most persistent bugs in backend work, because it appears at every boundary: a file read, a database column, an HTTP response, a name with an accent in it. The rule that saves you:

Comments, and what they are for

Some of the text is not for the machine at all:

java
// this line is ignored entirely
/* so is
   this block */

The compiler throws comments away. They exist purely for the next person, which is usually you in six months.

The useful discipline is what to write. A comment that repeats the code (// add one to i above i++) is noise that rots the moment the code changes. A comment that says why is the one worth having:

java
// Retry three times: the payment provider returns 503 during their
// nightly maintenance window and recovers within ~2 seconds.

Nothing in the code could have told you that, and without it the next person deletes the retry.

Misconceptions

  • "The IDE compiles my code as I type." It does compile continuously, which is why errors appear before you save — but the file on disk is still just text, and javac on the command line produces the same result. The IDE is a convenience, not a component of the language.
  • "Formatting affects behaviour." In Java, almost never. It affects whether a reviewer can see what you meant, which matters more often than you would guess.
  • "Encoding is legacy." It is 2026 and a name with an apostrophe still breaks somebody's export every week.
Progress is saved on this device and to your account when signed in.