Why are keywords like "final" and "mut" necessary?

Asked 2 months ago
Viewed 19 times This blog gives an example of using the final keyword in java to improve performance. Here is the example they give:

public static String concatNonFinalStrings() {
    String x = "x";
    String y = "y";
    return x + y;

public static String concatFinalStrings() {
    final String x = "x";
    final String y = "y";
    return x + y;

Apparently, the compiler will optimize concatFinalStrings() to just return "xy". Why can't the compiler do the same for concatNonFinalStrings()? x and y are limited in scope and they are never used anywhere else. Surely, then, the compiler should be able to treat those as if they were final? It's not like there can be some outside entity that may change the value of x and y, because they are inaccessible outside the function. The blog I've linked calls these "effectively final" and states that the compiler won't perform code optimizations on "effectively final" variables. Why not?

Furthermore, why do keywords like mut in Rust exist? Maybe it makes sense in Java where you can have public variables and you don't know what other .class files exist, but in Rust, if the whole thing is compiling at once, surely the compiler could just deduce which variables are mut by seeing which variables change their value? Do these now only exist for the sake of making the code more clear and not actually provide any sort of optimization?

asked 2 months ago

Correct Answer

First of all, even though the compiler could deduce a lot of things by being "smart enough", you have to take into account that compilation time is bounded. The compiler can't just try all the optimizations known to mankind to see if any fits, because that would be too long. Since the static optimization can be enforced by the final keyword, there isn't much point in the compiler doing that optimization for you (which would take time).

As for Rust, it's a similar answer (trying to figure out the minimum amount of variables that should be mutable for the code to run would be very long), with the addition that even if it was the case, the behavior would be very hard to predict, because a single change could completely modify the minimum set of variables that should be mutable for the code to be sound (if that even exists), and if that doesn't exist, the error reported would be horrible (because the compiler can't incriminate any particular piece of code, it's just that overall the code can't be made sound). To see some examples of this behavior, you could look at polymorphic variants in OCaml, where the compiler will infer the most general type for every value, but if it's not possible, error messages can quickly become horrendous.

A final argument as for explicit mutability in Rust is interfaces: sure, the compiler knows everything when compiling, but when I write a library and declare an interface (any interface, may it be a function signature or anything else), I may want to enforce mutability of a variable or, in the contrary, enforce its immutability, even without knowing how the consumer will use it. This allows the compiler to typecheck my library, including for mutability, even without knowing how it will actually be used.

And I didn't even mention readability: being explicit often also means being more readable.

answered 2 months ago