Sorry for the super simple question; I'm teaching myself java. The chapter talks about declaring variables as float or double. But it also writes that I need to put an F after the number or it is assumed a double.
float pi = 3.14F;
Is there a valid reason for needing the F or is it a legacy compiler issue or something? I'm not understanding why it's necessary if I've already declared a variable as float? (It implies the declaration is redundant or ignored).
What you declare it as doesn't matter. There are a couple of separate, independent steps. One of those steps is to evaluate the literal 3.14. The rules of the Java language says that the type of a floating point literal without an f or F after it is double. This is probably because floats are almost never used, so it keeps the code less cluttered to let double be the default rather than float.
Another step is to check if the expression on the RHS can be assigned to the variable on the RHS. The compiler sees that the type of the expression on the RHS is double, and that's all that matters to it. It sees that the LHS is float, and it knows that if you cram a double into a float, you may lose precision, so it complains.
The variable declaration has nothing to do with the type of the literal. Even though the variable is declared as a float, the literal is interpreted independently, and in place. Only when the assignment is evaluated do the semantics of the statement apply.
As a side note, Java does have special handling when the RHS expression is a constant. This handling allows int values to be assigned to byte variables, for example.... You can actually make an argument of why the designers decided to exclude this handling for longs, floats, and doubles.
Thanks for your help. It sort of makes sense but the logic of having both LHS and RHS declarations that can conflict with each other still a little confusing (I'm thinking too literally I guess). I'll keep plugging on and see if it sinks in a little more. Thanks again.
Keith Alexander wrote:Thanks for your help. It sort of makes sense but the logic of having both LHS and RHS declarations that can conflict with each other still a little confusing (I'm thinking too literally I guess). I'll keep plugging on and see if it sinks in a little more. Thanks again.
The idea is to keep things simple. For a language definition and a compiler implementation, things are simpler if we keep stuff like this decoupled, and don't have special cases. So the rules are:
1. A FP literal with no trailing F is a double. Always. (The always makes it simple, otherwise we have to check for special cases like how it's being used.)
2. If the RHS is of a type that cannot be assigned to the LHS without losing precision, it's an error.
2.1 Special case: Even if the type of the RHS is not compatible with the type of the LHS, as long as the RHS is a compile-time constant whose value does happen to fit into the LHS, allow it (for some types).
Rule 1 and rule 2 are independent of each other, which helps keeps things simple.
Rule 2.1 is a special case. We try to avoid those, as they complicate things, but in this case, it is worth it, because it saves of from having to cast when we do things like