Visualforce performs some coercion on values retrieved from getters to avoid certain error conditions. For example, consider this expression:
<apex:outputText value="Hello World" rendered="{!boo}" />
If boo (as above), were allowed to return null, an error would happen. Try rendering this in Apex Code to see what happens:
// Page constructor in Apex Code
public GetterSetterCon() {
if(boo) {
ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.INFO, 'Hello World'));
}
}
Note that this code crashes on page load with a null pointer exception, even though boo returns false in your example.
Visualforce is generally a bit more type-safe than Apex Code is, although you should still be aware of trying to render non-existent map keys.
You won't see this in the debug logs, because it doesn't occur in a way that's visible to the developers. Null renders as "nothing" in most cases, but renders as false in the case of boolean.
Running iterators, like apex:repeat, across a null list won't crash the page either; it treats it as if it were a simple empty list.
Perhaps the most important piece of advice I can give to a new developer is to never leave variables uninitialized. Other languages tend to either provide default values for uninitialized values, or provide compile-time errors. Apex Code and Visualforce do neither (generally, but there are exceptions), so you should always make sure you've initialized your variables. Special exceptions to default initialization are noted in the documentation.