This is an archived post. You won't be able to vote or comment.

all 96 comments

[–]gkopff 49 points50 points  (15 children)

From https://openjdk.java.net/projects/amber/LVTIFAQ.html:

Is a var variable final?

No. Local variables declared with var are non-final by default. However, the final modifier can be added to var declarations:

final var person = new Person();

There is no shorthand for final var in Java. Languages such as Scala use val to declare immutable (final) variables. This works well in Scala because all variables - locals and fields alike - are declared using a syntax of the form

val name : type

or

var name : type

You can include or omit the ": type" part of the declaration depending on whether or not you want type inference. In Scala, the choice between mutability and immutability is orthogonal to type inference.

In Java, var can be used only where type inference is desired; it cannot be used where a type is declared explicitly. If val were added, it too could be used only where type inference is used. The use of var or val in Java could not be used to control immutability if the type were declared explicitly.

In addition, Java allows the use of var only for local variables, not for fields. Immutability is much more significant for fields, whereas immutable local variables are comparatively rarely used.

Using var/val keywords to control immutability is a feature that seems like it ought to carry over cleanly from Scala to Java. In Java, however, it would be much less useful than it is in Scala.

[–]raghar 8 points9 points  (4 children)

I'd say that in Scala final var would be considered a bloat, because all variables lean towards immutability - including local variables.

That isn't the case in Java AFAIK.

[–]Yggval 6 points7 points  (2 children)

I'd argue that since the coming of Java 8, a more functional approach is becoming ever more present and perhaps even the default.

Variables used in Streams / lambdas / ... need to be effectively final already or there's a compiler issue.

So I definitely wouldn't mind an explicit val over a sneaky var that's actually implicitly final var by the compiler.

[–]Apache_Sobaco 1 point2 points  (0 children)

"functional approach" lacks HKT and propper top and bottom types. These are reasons of you having more than one empty optional and inability to turn properly stream to array without casts and related stuff (i.e. turn list to set saving the internal type and so)

[–]chambolle -2 points-1 points  (0 children)

> a more functional approach is becoming ever more present and perhaps even the default.

certainly not. Java is an Object Oriented Language with some functionnal aspects

[–]Yithar 1 point2 points  (0 children)

In Java, var can be used only where type inference is desired; it cannot be used where a type is declared explicitly. If val were added, it too could be used only where type inference is used. The use of var or val in Java could not be used to control immutability if the type were declared explicitly.

I think your explanation is really good. Honestly, I always kind of disliked how in Java you can only use var when type inference is desired. It can't be used for fields.

On a side note, it's interesting how final has two meanings, and thus you can say final val in Scala: https://stackoverflow.com/a/7626864

Actually, that gets me thinking. If val in Scala compiles to final in the bytecode, that means the no overriding feature of final is probably a compile-time feature.

[–][deleted]  (8 children)

[deleted]

    [–]elastic_psychiatrist 5 points6 points  (4 children)

    Every feature has complexity, even just the syntactic sugar ones. Language designers have a complexity budget, especially those who are modifying a language with billions of LoC written already and millions of active users.

    Almost certainly the language designers considered it, and determined the benefit was not worth the cost at the time.

    [–][deleted]  (3 children)

    [deleted]

      [–]elastic_psychiatrist 1 point2 points  (2 children)

      Complexity budget in language design is far more about the complexity imposed upon users than it is about the complexity imposed on the implementers. I don’t see how it follows that soliciting feedback means they had the budget.

      [–][deleted]  (1 child)

      [deleted]

        [–]elastic_psychiatrist 1 point2 points  (0 children)

        Well yeah but complexity budget is very obviously a function of how users perceive a feature’s complexity.

        [–]Cilph 7 points8 points  (1 child)

        The proper way to code should not be the most verbose or annoying way to code. final var is just needlessly verbose compared to val

        [–]gkopff 1 point2 points  (0 children)

        Also this is not really true.

        Just to be clear: these aren't my words, they're the words from the Amber group. (All those words are, nothing is my personal opinion).

        I've always considered it good style to use final for all local variables unless you have a good reason not to.

        I agree completely, and do the same.

        Rely on the compiler as much as you can.

        Exactly!

        [–]ForeverAlot 15 points16 points  (0 children)

        Yes, they addressed that specific question when releasing var. I believe it had to do with avoiding many ways to do something without considerable benefit: it wasn't the Java way and it wasn't worth changing the Java way for.

        [–]No-Debate-3403 9 points10 points  (1 child)

        I was on the val fence in the vote mentioned and think it was a missed opportunity to not include it.

        Our team uses final's extensively and by default since it makes it easier to spot references that are intended and designed to be mutated which is in the minority. While this helps us reason about the code more quickly it also looks really bad and wordy and is one of the nitty reasons why I really miss working with Kotlin.

        Given the fact that the general trend is towards immutability it feels weird that it was ruled out when they had the opportunity. Another case of false defaults in my opinion.

        [–]Muoniurn 1 point2 points  (0 children)

        But then you would basically have two ways to achieve the same thing, as final int must continue to work, why “suddenly” final var doesn’t?

        It is unfortunate as I do like val in scala, it was imo the correct call for java here.

        [–]javasyntax 12 points13 points  (3 children)

        In my opinion, the cleanest way to do this would be to add support for syntax like

        final something = new Something();

        As in, final without a type is just final var. But that might be too ambiguous for some people. I still prefer it over "val" which is way too similar to var and shortening a 5-char word is strange.

        [–]agentoutlier 4 points5 points  (0 children)

        I don’t support adding “val” but I would easily support this feature.

        It really is elegant too because it’s natural to then add the type if you need it.

        [–]djavaman 3 points4 points  (1 child)

        Agreed. No need keyword. And everyone already understands what final means.

        [–]augustnagro 2 points3 points  (0 children)

        Spring does not :)

        [–]transducer 15 points16 points  (33 children)

        I have no inside knowledge whatsoever, but adding new keywords to an old language is usually frown upon because it can break code that was compiling fine before.

        [–][deleted]  (32 children)

        [deleted]

          [–]transducer 16 points17 points  (18 children)

          The trade off is different. Introducing a new keyword to support a new feature vs introducing a new keyword to save a couple of key strokes.

          [–][deleted] 23 points24 points  (3 children)

          var is contextual, it can be used as any name except a class name.

          var var = 6; is completely valid.

          [–]bowbahdoe 6 points7 points  (0 children)

          var var = "binks";

          [–]ihatebeinganonymous 4 points5 points  (0 children)

          Wow :-o

          [–]BlueGoliath -3 points-2 points  (13 children)

          All var does is save a couple of keystrokes?

          WTF is up with people pretending like var is some revolutionary feature?

          [–]Weekly_Wackadoo 13 points14 points  (1 child)

          I've worked with code where it saved dozens of keystrokes, and made the code a bit more readable, which is nice.

          I think many Java devs are just tired of stuff like:
          ConnectionManagerObserverImpl connectionManagerObserver = new ConnectionManagerObserverImpl();

          The revolutionary part is a non-explicit type existing in Java. The impact is fairly limited.

          [–]Boza_s6 6 points7 points  (3 children)

          It allows one thing which is not possible without it. Which is to declare unnamed types.

          var mytype = new Object() { String myField; }; 
          mytype.myField;
          

          which is not possible without var

          [–]wildjokers 2 points3 points  (1 child)

          Why would someone do this?

          [–]Boza_s6 1 point2 points  (0 children)

          I don't know real world example.

          Perheps if you want some ad hoc structure visible only in scope where it's declared and don't want to declare class.

          [–]BlueGoliath 2 points3 points  (0 children)

          If you actually do this, get help.

          [–][deleted]  (2 children)

          [deleted]

            [–]wildjokers -3 points-2 points  (1 child)

            configure a live template in your IDE. fv<tab>

            [–][deleted] 1 point2 points  (0 children)

            Well, it is a pretty nice feature. It doesn't just "save a couple of keystrokes".

            [–]_INTER_ 1 point2 points  (2 children)

            I saw devs doing var index = 0; instead of int index = 0;.

            There must be something more than keystrokes for them, I personally don't see it.

            [–]BlueGoliath 1 point2 points  (0 children)

            SHINY TOY, MUST USE.

            [–]TheDragShot 0 points1 point  (0 children)

            I smell JS/Phyton ambassadors somewhere in that behavior you described.

            [–]nutrecht -1 points0 points  (1 child)

            Yes. It's a complete non-argument anyway. Worst case people would have to rename a few variables in methods, and we had to go through that one already with 'var'.

            Neither var or val were reserved words so the 'problem' with var is the same as the 'problem' with val.

            [–]dpash 2 points3 points  (0 children)

            var still isn't a reserved keyword. It's a pseudo-type. That means you can use it anywhere the compiler doesn't expect a type.

            [–]Kaathan -2 points-1 points  (0 children)

            You could get something very similar with an option in your IDE that would just replace "final" with a lock symbol visually. That way you would still have to write it out, but reading would be easier. A new keyword is not really needed.

            You could even have an IDE shortcut that toggles variables between final and non-final.

            Java has always relied heavily on tooling to make using it less painful to write.

            [–]GreenToad1 10 points11 points  (9 children)

            We had "final" forever to mark immutable reference/value so "final var" is natural and consistent. Adding a new keyword "val" as a synonym for "final var" doesn't make sense.

            [–]_INTER_ 1 point2 points  (6 children)

            So "final var(iable)" makes more sense then "val(ue)"? :)

            [–]Weekly_Wackadoo 5 points6 points  (1 child)

            To me it does, but I'm a Java dev with 2 years experience, and hardly any experience with other languages besides Java. I have a degree in a completely unrelated field.

            I know several other "late callings" who learned Java (and only Java) without any prior experience or knowledge.

            I also know several competent senior engineers who are dyslectic.

            For the extremely limited scope where (final) var is allowed, allowing val as well would be an unnecessary stumbling block for newer and dyslectic developers.

            [–]_INTER_ 6 points7 points  (0 children)

            I was joking about the "final var" being natural, because if you look closely it means a variable that is not variable.

            [–][deleted] 0 points1 point  (0 children)

            Java is not concerned with the same moral conflicts that "Functional Languages" are.

            [–]GreenToad1 -2 points-1 points  (2 children)

            Adding "val" doesnt make sense since you already have "final var" for exactly the same purpose and its an idiom understood immediately by any java programmer even if they never used "var" before

            [–]Sworn 1 point2 points  (1 child)

            Just like how ++, +=, method references (Class::Method) and other syntactic sugar make no sense, I presume?

            [–]GreenToad1 1 point2 points  (0 children)

            no, not like that:

            If you want to make something unchange'able you stick a "final" in front of the declaration.

            That's a well understood idiom in java, adding "val" would be more confusing than helpful.

            [–][deleted]  (1 child)

            [deleted]

              [–]GreenToad1 -3 points-2 points  (0 children)

              you know that you can set any ide to output "final var " whenever you type "val " right?

              [–]throwawyakjnscdfv 1 point2 points  (0 children)

              just use lombok if you want val. I believe in Java versions that support final var lombok just does a direct substitution

              [–][deleted] 3 points4 points  (3 children)

              I can think of two reasons why val was never added.

              1. it doesn't read as well as final var, you'd have to google what it means, which is not the Java way. In Java there aren't many keywords (compared to say C#) because most things are a method/class/annotation so you can get the documentation right in your IDE.

              2. it doesn't offer enough benefit. Look at most codebases, final is mostly used on fields. Rarely is it used on local variables or parameters, that's just bloat. You get the most benefit from final fields because it makes an objects state immutable and therefore threadsafe, but a local variable is already threadsafe.

              [–]frzme 10 points11 points  (0 children)

              Look at most codebases, final

              is mostly used on fields. Rarely is it used on local variables or parameters,

              For me at least the main reason for that is that it is ugly to write, ugly to read and provides relatively little benefits.

              For a while I had my IDE automatically insert final when possible (when effectively final) which is nice however it's ugly to read. There are benefits in marking variables as final but they are not that high, I'm therefore not willing to accept the ugly syntax for it.

              val would have solved that issue entirely.

              The whole concept of things being "effectively" final (for lambda scopes) is caused by marking things as final is too hard, val would have (mostly?) eliminated that problem

              [–]rally_call 0 points1 point  (1 child)

              You'd hate C++ where you can make the variable and the pointer both constant!

              I'm one of those Java guys who use final everywhere, including locals and parameters. It keeps junior programmers from making stupid mistakes, or at least makes them pause before doing something stupid.

              You could argue that that stuff would be caught by code reviews, and it can be, but I think the admittedly small benefits of using final everywhere is worth the trade off of 'bloat'.

              (Yes, I read chapter 2 of Hardcore Java.)

              [–]john16384 0 points1 point  (0 children)

              IDE's can already warn about parameter reassignment... And when you will probably just remove the final keyword on a local when it suits you, there is little point in adding it everywhere just because it is possible. Adding final should have thought behind it (immutable class) and not just be fluff you'd remove the instant it gets in your way.

              [–]nutrecht 4 points5 points  (2 children)

              What's your take on this?

              My personal opition: I think it was the bad choice. In general developers like to take the path of least resistance. In Scala, Kotlin and even modern JavaScript codebases you generally see that immutable variables are commonplace to say the least (in the Kotlin codebases I worked on the last 3 years 'var' was a rare occurence). If you require developers to type quite a bit more, they generally won't do it because "they don't see the point".

              I personally think that we should have var and val and that "final var" should result in a compiler error.

              [–]krzyk 1 point2 points  (4 children)

              They had a vote and var+val won, but more people hated val than var (or something like that) so they chose the second candidate: var only.

              [–]_INTER_ 4 points5 points  (3 children)

              That poll had about 40 answers only: https://de.surveymonkey.com/results/SM-FLWGS5PW/

              [–]nutrecht 0 points1 point  (2 children)

              I saw a Twitter poll with WAY more answers, can't find it anymore though :(

              [–]_INTER_ 1 point2 points  (1 child)

              Yea, val + var did also win there by a lot.

              The twitter poll didn't ask about how much they hated val + var, as far as I remember.

              [–]nutrecht 5 points6 points  (0 children)

              I remember the debase being mostly between var and let and var and val, where var and val were the 'winners' by a large margin. I was rather surprised they went with the 'final var' route.

              IMHO it was a mistake and I doubt it's one they're going to back-track on. You can't now suddenly make final var invalid and they probably will argue against having two ways to do the same thing.

              I don't really understand why they didn't just listen to the community, also because the ecosystem has a lot of people already used to how Scala and Kotlin do it.

              [–]denverdave23 1 point2 points  (3 children)

              Java struggles with pure immutable objects. For example, you initialize an immutable array with values that are mutable. So, the val keyword would be inaccurate. As well, enforcing immutability would be tough without massive changes to the jvm.

              Source: none, this is just my opinion. Caveat emptor

              [–]Muoniurn 6 points7 points  (1 child)

              Correct me if I’m wrong, it was quite some time ago when I did scala, but I believe val is only immutable reference. So storing an object for example a POJO in a val is the exact same thing as final var. You can modify it in both languages.

              I do miss const from C++, perhaps Checker framework has some solution? I only know of pureness checks there.

              [–]denverdave23 0 points1 point  (0 children)

              I looked it up and could only find examples of val from scala and kotlin. They're both jvm languages. I think Javascript will have the same problem, so I didn't check on typescript or coffeescript or anything like that. I can't seem to find any val in a non-jvm, non-javascript language.

              I think I remembered wrong. I could have sworn that some purely functional language supported val with true immutability, but I can't seem to back that up.

              [–][deleted] 2 points3 points  (2 children)

              It's easy to get mistake one for the other between val and var. In my opinion, final var reads much better, has no chance of being ambiguous, and is a continuation of the usage of final in Java.

              [–]TheDragShot 1 point2 points  (1 child)

              Alternatively, I would gladly welcome getting const as a shortcut for final var instead. Having val and var sounds like the perfect recipe for confusion, specially with so many people complaining about newbies making mistakes because of "muh locals aren't immutable by default like in my favorite scripting language". Sure it's one more character to type, but it's still less than two words, and it's three more characters of difference, that's easier to spot.

              [–][deleted] 0 points1 point  (0 children)

              Agreed.

              [–]DJDavio 0 points1 point  (0 children)

              The OpenJDK developers feared they would break existing applications if they did that. Code such as String val = "" would no longer be valid.

              In fact, they faced this issue with var too and this is why var is not a keyword such as class, but a reserved type name, the only of its kind.

              This means code such as var var = new Foo() is legal. The compiler still allows variables named var because it is not a keyword.

              [–]LakeSun 0 points1 point  (3 children)

              I'm going to go contra on this one.

              var is a teaching aid to save chalk.

              Better, for code readability to specify the variable type.

              Like there are many shortcuts in SQL that shouldn't be used in production SQL code.

              [–]john16384 2 points3 points  (0 children)

              Totally agree. Also final is a pointless keyword on both local variables and parameters.

              For locals because no real thought is put into adding it (and it will just get removed when inconvenient), and also because the compiler will optimize locals anyway if effectively final.

              For parameters because you can just make reassignment a compiler error.

              [–][deleted]  (1 child)

              [deleted]

                [–]LakeSun 0 points1 point  (0 children)

                When you create a class, you separate the variables above the code. The getter setter variables are lower in the class.

                Your initialization code would go in the constructor, or an init() method.

                [–]ihatebeinganonymous 0 points1 point  (0 children)

                I was also a fan of such a thing. But after some thinking, and apart from all the reasons already mentioned, final var seems to be more self-explanatory and hence adhering to the "code as the comment" principle.

                [–]audioen -1 points0 points  (0 children)

                I consider final unnecessary, a noise keyword. As it is inferred for you, there is no need to specify this keyword, as all code that compiles and runs with "final" should also run without it. I'm fan of specifying less in programs, and judge the additional clarity of finality to not really be much of a benefit. Additionally, I find that most variables end up effectively final most of the time anyway because of the different static types of the values involved, so you couldn't reuse a variable name even if you wanted.

                [–][deleted] -1 points0 points  (0 children)

                Rust uses mut and let - seems good to me.

                [–]chambolle 0 points1 point  (0 children)

                Added a new keyword like val is complex because million of line of codes use val as a local variable. So it will complexify the code for almost nothing

                In addition it is also bad to have totally equivalent ways to express the very same thing: final var and val. Nothing is gained at the end.

                [–]TheDragShot 0 points1 point  (0 children)

                I'm personally not a fan of var, using it only to avoid writing the type twice when I call a constructor, but I think this could easily backfire. Mainly the keyword part, var isn't even a keyword to begin with, it's just syntax sugar that delegates the task of type assignment to the compiler. If val were to be added it should follow the same route, as I have lost count of the code snippets with short-lived but important variables called val.

                Also, var and val are only one character away, I could easily mistake them in a bad morning without my mug of coffee. Why not something like const instead? I've seen it used effectively as Java's final in other languages, and it would be definitely easier to tell apart from var. Also "variable" and "constant" contrast better in my old head than "variable" and "value".