Should local variable type inference be added to Java? This is the question being pondered right now by the Java language team.
Local Variable Type Inference
JEP-286 proposes to add inference to local variables using a new psuedo-keyword (treated as a "reserved type name").
We seek to improve the developer experience by reducing the ceremony associated with writing Java code, while maintaining Java's commitment to static type safety, by allowing developers to elide the often-unnecessary manifest declaration of local variable types.
A number of possible keywords have been suggested:
- var - for mutable local variables
- val - for final (immutable) local variables
- let - for final (immutable) local variables
- auto - well lets ignore that one shall we...
Given the implementation strategy, it appears that the current final
keyword will still be accepted in front of all of the options, and thus all of these would be final (immutable) variables:
- final var - changes the mutable local variable to be final
- final val - redundant additional modifier
- final let - redundant additional modifier
Thus, the choice appears to be to add one of these combinations to Java:
- var and final var
- var and val - but final var and final val also valid
- var and let - but final var and final let also valid
In broad terms, I am unexcited by this feature and unconvinced it actually makes Java better. While IDEs can mitigate the loss of type information when coding, I expect some code reviews to be significantly harder (as they are done outside IDEs). It should also be noted that the C# coding standards warn against excessive use of this feature:
Do not use var when the type is not apparent from the right side of the assignment.
Do not rely on the variable name to specify the type of the variable. It might not be correct.
Having said the above, I suspect there is very little chance of stopping this feature. The rest of this blog post focuses on choosing the right option for Java
Best option for Java
When this feature was announced, aficionados of Scala and Kotlin naturally started arguing for var and val. However, while precedence in other languages is good to examine, it does not necessarily apply that it is the best option for Java.
The primary reason why the best option for Java might be different is history. Scala and Kotlin had this feature from the start, Java has not. I'd like to show why I think val or let is wrong for Java, because of that history.
Consider the following code:
public double parSpread(SwapLeg leg) { Currency ccyLeg = leg.getCurrency(); Money convertedPv = presentValue(swap, ccyLeg); double pvbp = legPricer.pvbp(leg, provider); return -convertedPv.getAmount() / pvbp; }
Local variable type inference would apply fine to it. But lets say that the type on one line was unclear, so we choose to keep it to add clarity (as per the C# guidelines):
public double parSpread(SwapLeg leg) { val ccyLeg = leg.getCurrency(); Money convertedPv = presentValue(swap, ccyLeg); val pvbp = legPricer.pvbp(leg, provider); return -convertedPv.getAmount() / pvbp; }
Fine, you might say. But what if the code is written in a team that insists on marking every local variable as final.
public double parSpread(final SwapLeg leg) { val ccyLeg = leg.getCurrency(); final Money convertedPv = presentValue(swap, ccyLeg); val pvbp = legPricer.pvbp(leg, provider); return -convertedPv.getAmount() / pvbp; }
Suddenly, we have a mess. Some parts of the code use final to indicate a "final" (immutable) local variable. Whereas other parts of the code use val. It is the mixture that is all wrong, and it is that mixture that you do not get in Scala or Kotlin.
(Perhaps you don't code using final on every local variable? I know I don't. But I do know that it is a reasonably common coding standard, designed to add safety to the code and reduce bugs.)
Contrast the above to the alternative:
public double parSpread(final SwapLeg leg) { final var ccyLeg = leg.getCurrency(); final Money convertedPv = presentValue(swap, ccyLeg); final var pvbp = legPricer.pvbp(leg, provider); return -convertedPv.getAmount() / pvbp; }
This is a lot more consistent within Java. final continues to be the mechanism used everywhere to get a final (immutable) variable. And if you, like me, don't worry about the final keyword, it reduces to this:
public double parSpread(final SwapLeg leg) { var ccyLeg = leg.getCurrency(); Money convertedPv = presentValue(swap, ccyLeg); var pvbp = legPricer.pvbp(leg, provider); return -convertedPv.getAmount() / pvbp; }
I understand the objections many readers will be having right now - that there should be two new "keywords", one for mutable and one for immutable local variables and that both should be of the same length/weight (or that the mutable one should be longer) to push people to use the immutable form more widely.
But in Java it really isn't that simple. We've had the final keyword for many years. Ignoring it results in an unpleasant and inconsistent mess.
Summary
I don't personally like local variable type inference at all. But if we are to have it, we have to make it fit well within the existing language.
I argue that val or let simply does not fit Java, because final already exists and has a clear meaning in that space. While not ideal, I must argue for var and final var, as the only combination on offer that meets the key criteria of fitting the existing language.
Would you still have to use traditional local definition if you wanted to limit the type inference, e.g. suppose:
ReplyDeleteShape shape = getShape(); // where shape can have the usual subclasses
Now, I want to only use methods defined in Shape, not in the subclasses in the rest of the block.
Not, for example, assuming that it is a Triangle.
If I did this :
var shape = getShape();
Then would the type inferred actually be the subtype of the actual instance, or is it still limited to Shape?
The question is, if I'm not mistaken, what the signature is of getShape(). If it is "Shape getShape();" the inferred type will be Shape.
DeleteTo me the problem is simpler. This feature is all about making the writer's job easier at the expense of the reader. In my opinion this trade-off should never happen.
ReplyDeleteIt's not a zero-sum game. You *can* make the writer's job easier *without* sacrificing readability.
DeleteAssuming you follow good coding practices, `var shape = getShape();` isn't any less readable than `Shape shape = getShape();` -- only possibly more so.
agree.. It looks funny, like JAVA is becoming less strongly typed while PHP goes the other way.
DeleteThe problem is when getShape() does not return a Shape. You don't know for sure and at one glance what it returns. You need to look up its definition.
DeleteTo me the problem is simpler. This feature is all about making the writer's job easier at the expense of the reader. In my opinion this trade-off should never happen.
ReplyDeleteSome sanity into this argument, if your code is hard to read, you have not done your job!
DeleteEntirely agree with mebigfatguy...
ReplyDeleteCan we do something to stop this madness from entering the Java world ? I really do not see the point in it. And I say it as a casual Groovy dev, who misses the types as soon as the scripts spans a few screens
This comment has been removed by the author.
ReplyDeleteI haven't thought about it this way yet, but then again, if that's the worst that'll happen (some additional meaningless bikeshedding about style), then I'd say you don't really have an argument against this feature :)
ReplyDeleteI agree, I have voted on var/ final var
ReplyDeleteIdeally, the semantics would be the opposite of Java's, namely, the absence of a keyword for immutability and the presence of a keyword for mutability.
ReplyDelete"I don't personally like local variable type inference at all".
ReplyDeleteWell, it is sad that all code examples of the antagonists don't apply complex generic types.
It is true that the inference feature does not show its power with types like 'Shape' or 'Money'.
Inference is even more a valid feature considering the C-style leading type syntax, which does not fit well with generic type expressions in my opinion.
And it is like with EVERY feature: Use it wise to produce maintainable code!
But it would be sad to not have this option. Java started to be annoying more and more and has to do something to step out of this darkness. Better type inference is one important step in that direction.
Encouraging more final-ism in code another. Unfortunately Java still lacks the big picture, i.e. an adequate collection library with more immutability.
BTW Non-final method parameters are a big annoyance and source of bugs too.
My 2 cents:
ReplyDeleteIn my opinion, "final var" doesn't quite encourage the use of final immutable values as strongly as something like "let" or "val". In other words, developers would be more inclined to just write "var" and forget the final keyword. However, if you have a dedicated keyword, you may be more thoughtful when you declare the variable.
I'm also okay with the mixture. When I take a look at the mix of vals and final variables, I feel like I see what the developers intent is there. It's exactly what you said, the dev wanted it a val, but felt that explicitly naming the type was clearer.
Go with "let" and "var". Somehow I feel like "let" is more established among languages than "val".
(And I'm assuming here that we want to encourage the use of immutable variables where possible.
Citing "Effective Java", Joshua Bloch's recommendation is to favor immutability:
Classes should be immutable unless there's a very good reason to make them mutable.)
Bloch's comment was clearly not about local variables, which is what this JEP is about. Using immutable objects is a good programming practice but using "final" local variables is essentially a matter of coding style.
DeleteYou're right, but having *everything* immutable is clearly even better. Sure, immutability of local variables is not that important. The problem is that with "final", Java went the wrong direction. Now, using "final" increases the readers overhead and barely caries its weight, which makes it matter of style. Having everything final by default and using a keyword for the opposite would be much much better, but it's too late.
DeleteLet's leave trivialities such as developer satisfaction to such languages as C#.
ReplyDeletewhats the difference between
ReplyDeleteVar someVariable
And
Object someVariable
?
Hiding the type for everyone reading the code.
Delete@Mark from what I understand, with the new var-or-whatever keyword, you will be able to call your real type methods on the variable, whereas with 'Object', you are limited to the methods defined on the "Object" class.
ReplyDeleteSo there IS a difference.
But I still can't understand why hiding a type that IS there, that the compiler can infer,is a good thing. Yes Java is verbose. BUT it is explicit. I tend to READ much more code than I write just because before modifying an existing code base you have to understand it. And this will REALLY make my day harder.
So var is an object you don't have to cast?
DeleteSounds like a feature no sane programmer would ever use and every software house worth its salt would forbid.
It's just a feature allowing to write code faster. Nothing is cast. The compiler will replace your "var" with "Object" because he can infer it from right side.
DeleteThe compiler will replace "var" with the inferred right side's type. That is a huge difference.
Delete@Fraaargh
ReplyDeleteOne place where it makes sense to use var/let is when you're calling a constructor or factory method and the return type is clear.
var nums = new ArrayList();
Or
var fruits = Arrays.asList("Apple", "Banana", "Orage");
In the above cases, it's pretty clear the type of the variables. This reduces the redundant type declaration in those kinds of situations.
Take a look at the top voted answer on this stackexchange post .. I think he makes a pretty compelling argument for the use of local type inference.
In his example for loop, there are more types than actual code. You can see there that the excessive typing information is actually detracting from the logic that is performed in the code. Using var or let in that loop, I think the types would still be clear to a reader, would reduce the code down to just the essential logic, and would still maintain the same level of type safety.
ArrayList nums = new ArrayListHashSet();
DeleteBeing replaced with
Var nums = new ArrayListHashSet();
Would do nothing good.
I'm not sure where you got ArrayListHashSet(), but, ok, how about:
DeleteHashMap<String, HashMap<String, ArrayList<String>>> map = new HashMap<String,HashMap<String, ArrayList<String>>> ();
vs
var map = new HashMap<String,HashMap<String, ArrayList<String>>> ();
Do I really need to specify that type a second time around?
And keep in mind, my variable map still has exactly the right type, and the compiler knows it. I've not lost any information here.
->Do I really need to specify that type a second time around?
DeleteYou can already do.
Object map = new HashMap>> ();
Which helps about as much as var, without the bugs.
Both are bad code though. That's the whole point of classes.
That's not even valid Java...
DeleteAnd if you really thing using Object is equivalent to using var, you don't have the slightest idea what you're talking about.
Mark, I'm not sure you are getting the idea yet. Using:
Deletevar x = new ArrayList<Integer>();
is drastically different than
Object x = new ArrayList<Integer>();
In the former, the type of the "x" variable is "ArrayList<Integer>" and in the later, the type of "x" is Object. Using Object here would be a horrible idea, and that's not what anyone is proposing with the use of var.
I feel like you're spreading some FUD, with concerns about type-casting, sub-classing, and security here that just simply aren't issues with this proposal.
Correct me if I wrong but in Java 7 you replace
Delete> HashMap>> map = new HashMap>> ();
with
HashMap>> map = new HashMap<> ();
Thx,
Andrei H.
Mark, I'm not sure you are getting the idea yet. Using:
Deletevar x = new ArrayList();
is drastically different than
Object x = new ArrayList();
nope. in the second it is still an integer arraylist and instanceof arraylist integer will return true.
and both will always be objects. since all java classes extend the class Object.
sounds like a lot of people do not really understand java type hierarchies.
DeleteHashMap<String, HashMap<String, ArrayList<String>>> map = new HashMap<String, HashMap<String, ArrayList<String>>> ();
vs
var map = new HashMap<String, HashMap<String, ArrayList<String>>> ();
First and foremost, rethink your life if you are using collections this way (a class with some behavior maybe ) ... however the readability argument is somewhat off:
the actual difference is :
Map<String, HashMap<String, ArrayList<String>>> map = new HashMap<> ();
vs.
var map = new HashMap<String, HashMap<String, ArrayList<String>>> ();
Also chances are something like that would be IoC injected anyway ...
I'm guessing that the benefit of local var/let/val, it's more like when you have some ugly API, and you do not want to waste time getting deep into it, to get at the narrowed implementation, you just get a local reference to use, more for side effects, then for actual reference i.e as an argument to a log message and into the next ugly call .
Also this "white tower" "final" enforcement by the language syntax is unnecessary, if that's what you want, put it where it belongs: compiler warning, or use IDE style enforcement. If you use eclipse, you can add a save action that will add final to your local variables, method arguments, etc. Since we have the qualifier in the language, it's better to have one "var" declaration and use "final" to make it immutable (This will be consistent with the reset of the language). This is better for readability since it's following existing Java conventions. Also, what's the difference between val/let, or var/auto ? Pick one, maybe two (not happy with the second choice, violates KISS) if you MUST enforce final.
my 2 cents,
Nick
@Anonymous
ReplyDeleteI'm not at all convinced by your first example. Yes the return type is clear, but is it really enough an argument to add yet another keyword, yet another subject of debate in teams (when should we use it, when should we not) ? I don't think so.
Your second point with the stackexchane post is more interesting. I agree that this kind of code may benefit from new keywords. But franckly, the problem is not really with "top-coders" dealing with this kind of code. The real problems lies with casual coders who will abuse the new keywords, who will spark endless debate whether to use it or not because they have never red any post on the internet to even try to understand when we should or should not use it. The fact is that Java is #1 language in the world and the real world is not only top-notch coders but casual coders that will have yet another keyword to learn and yet another way to produce bad code because of mis-using/abusing a keyword they don't understand the power of.
This is what worries me :/
Second that.
ReplyDeleteIn fact I don't see how this would work in any language that allows subclass's at all.
Lots of java subclasses have functions with the same name that do different things (e.g. getLast())
Completely ambiguous in a subclass that allows getlast on the last entry added who's parent class gets just the last element in an array (heaps for example).
I find the idea of "well, if it's not worse than now, why not just add X" to be really, really undefensible position: adding a no-net-gain feature (which nonetheless must then be supported by or tooling, understood by all developers) is a losing proposition.
ReplyDeleteIf you actually think this is net positive, that's different -- I can't blame anyone for advocating it -- but please, please do not think of "hey, it's free, just add it". No such thing as a Free Feature: there is cost associated with adding anything, so there absolutely MUST be something to warrant paying that cost.
I think Java's lack of type inference was acceptable until lambdas were added to the language (storing a lambda into a local variable forces you to deal with a very verbose type declaration, defeating the compactness of the lambda syntax).
ReplyDeleteRegarding situations where declaring a type explicitly is beneficial, Java should take a page from the Xtend language, and allow:
val Money convertedPv = ...
Also, if a new keyword were to be avoided, why not use final:
final ccyLeg = leg.getCurrency();
final Money convertedPv = presentValue(swap, ccyLeg);
final pvbp = legPricer.pvbp(leg, provider);
Interesting point. Personally I appreciate var and val. I think it 'final' will be still important. It will be clear that 'final' is related to inheritance and 'val' denotes an immutable value. I can't imagine that anyone will write the noisy 'final var'. It does not align well optically and code will look cluttered. The name 'val' is nice because it stands for 'value' which is the most important building block for immutable, functional programs.
ReplyDeleteI think we don't need it, we're better off without. It's more clear that way, more explicit. A few keystrokes more or less won't make a world of difference.
ReplyDelete@Alexandru A few keystrokes? I've generic code of nested collections, tuples or functions, where the LHS of a variable declaration spans multiple lines. I'm not able/willing to write that without the help of an IDE. Also it does not help me to see it in code reviews. The opposite is true. For simple types you may be right.
ReplyDeleteWhich you prefer to actually writing a proper class like you are supposed to because?
DeleteTuples are proper return types of functions. In other cases I write proper classes, like here (domain: structural pattern matching): https://twitter.com/danieldietrich/status/708286770673295360
DeleteAnd by the looks of it all that could be replaced with about 10 lines of closed and a couple of instanceof's
DeleteWhy would you want to obfuscate the code like that? It's much clearer to just work with a HashMap> directly.
Delete@Mark Parer: I can understand your point of view. In the case of deeper nested checks down the object hierarchy rabbit hole the if-cascades do not help, though.
Delete@Anonymous: Structural pattern matching is a great thing. Imagine to decompose URLs into their parts and match specific conditions. Or recursively decompose a complex object in order to ensure specific conditions.
Please read:
http://blog.javaslang.io/pattern-matching-essentials/
http://blog.javaslang.io/pattern-matching-starter/
Java has so many possibilities. We observe a convergence of programming languages. The helpful features will make it. Please don't stop progress.
How don't they help?
DeleteI don't see that doing anything more complicated than trying to identify what class something is by determining its structure.
That can all be replaced with explicit class's, an if instance of, then a cast.
Something like
Deleteif(x instanceof Y) {
Y y = (Y) x;
// ...
}
I use it to determine what state an (immutable) object has, even if I know the class/type.
DeleteHere is some fantasy code that is possible:
// Match a person that has forename "Mark", lastname *, Address: { street: *, number: > 42 }, Phone: +49xxxx,
Match(person).of(
Case(Person("Mark", $(), Adress($(), 42), Phone(startsWith("+49"))), person -> ...)
)
Or even filter all persons that match a specific criteria:
val personList = ...;
val filteredPersons = personList.collect(
Person("Mark", $(), Adress($(), 42), Phone(startsWith("+49")))
);
The compiler will not compile personList.collect(...), if personsList does not contain Person elements because the Person pattern is type-safe.
Please show me a concise Java program using only if statements et al. that does the above. Please note that null-checks are implicitly included above!
s/Adress($(), 42)/Address($(), $(num -> num > 42))/
Deletepublic class var extends Object{
DeleteObject value;
public var(Object value){
this.value=value;
}
public Object add(Object val){
if(value instanceof String && val instanceof String){
return ((String)value)+((String)val);
}
else if(value instanceof String || val instanceof String){
if(value instanceof String)
return ((String)value)+((Number)val);
else
return ((Number)value)+((String)val);
}
else if(value instanceof Number && val instanceof Number){
return ((Number)value).doubleValue()+((Number)val).doubleValue();
}
else return null;
}
public static void main(String[] args){
var val1=new var("hello");
var val2=new var("world");
var val3=new var(10);
var val4=new var(30);
System.out.println(val1.add("hello"));
System.out.println(val1.add(" world"));
System.out.println(val2.add(10));
System.out.println(val3.add(10));
System.out.println(val4.add(30.5));
}
}
now, letting us overide opertors... That's something entirely different.. and would be very useful.
DeleteI have a big wishlist of features but operator loading is not on that list:
Delete- type inference (var/val)
- value objects (will come with java 10)
- better type system (declaration site variance, higher-kinded types)
- lazy evaluation (call by name parameters)
- tail recursion (technically possible since bytecode changes in jdk 7 I think)
- native pattern matching
- for-comprehensions
- extension methods
- ...
also, see
Deletehttps://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html
-> type inference (var/val)
DeleteThe above implementation is fully compilable, and gives you var (save in a file called var.java javac var.java then java var, using it would probably get you fired tho. Since all it does is create a million opportunities for bugs.
->higher-kinded types
You mean like Integers and Doubles are instances of Number? we've had that since the earliest versions.
> also, see https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html
DeleteThe collect method I mentioned above is unrelated to java.util.stream.Stream. I've create a new collection library for Java 8+, comparable to those of Clojure and Scala: http://static.javadoc.io/io.javaslang/javaslang/2.0.1/javaslang/collection/package-summary.html
> The above implementation is fully compilable...
Don't know what you mean. That code is clean and readable ;) Nothing compared to what is possible with Scala: https://twitter.com/danieldietrich/status/706252064410746880
> You mean like Integers and Doubles are instances of Number?
No, please read this: http://adriaanm.github.io/files/higher.pdf
--
Let's stop this discussion here. I understand your points and that you do no want to have that feature.
Happy easter,
Daniel
->No, please read this:
DeleteJava IS NOT a functional programming language.
Which is why it is the #1 deployed language in the world.
if you need functional programming there are a ton of implimentations, such as you say clojure
These however are really not suitable for secure, enterprise deployment. imho, no functional language ever will be, because they are impossible to secure.
And especially when they offer nothing that cant be achieved more reliably and with less bugs using org.apache.math.
->Don't know what you mean. That code is clean and readable ;)
That code is, but anything that used it would be prone to bugs, and highly exploitable.
Please watch:
https://www.youtube.com/watch?v=zKuFu19LgZA
for example
Deleteadding
List numbers = Arrays.asList(1, "2", 3, new var(66));
for(Object number:numbers){
var v=new var(number);
System.out.println(v.add(v.value));
}
to the above main function.
And ok, sure you can "fix it". But the point is
1. It offers nothing
2. It fundamentally will add bugs that breaks the java security model
3. As long as we cant overide operators (to make, for example, System.out.println(val4 + 30.5); actually possible) it will do the precise opposite of what is intended.
4. adding the capability to overide operators will add this capability without breaking the security model (possibly, I suspect the security model is why operators can't be overidden)
How about using 'var' and 'val', but allowing to optionally specify the type in addition? That way, all of the following would be legal:
ReplyDeletevar x = 5
val x = 5
var int x = 5
val int x = 5
int x = 5
final int x = 5
This comment has been removed by the author.
ReplyDeleteTrying to make Java more like JavaScript, Scala or C# won't keep people from using those instead. Trying to make progress on modernized and improved frameworks and APIs, especially in the Java EE space would. Otherwise that won't keep anybody from using Angular, Node or other environments with these keywords already in place.
ReplyDeleteI disagree with this. Primarily a Java developer, I've also spent a great deal of time studying Javascript, Scala, and Clojure. Doing so is enlightening, I'm learning a lot and having fun, and yet I still come back to Java. However, I believe I come back to Java as a better programmer.
DeleteI think the Java community is wise to look to other languages and carefully selecting good ideas from those languages. Some of the newer features like lambdas, streams, and now local type inference, make programming fun! That's critically important if you want to onboard new Java developers or retain existing. And increasing the programmer satisfaction doesn't have to mean you're making the language any less capable, less secure, or less enterprise worthy.
What about having type inference for final variables only and use "final v = expr;"
ReplyDelete1. No new keywords. 2. Final declarations would be usually shorter than mutable ones.
+1 however I would not be against one new keyword (var or auto) not 3 or four ...
Delete+1 however I would not be against one new keyword (var or auto) not 3 or four ...
DeleteThis comment has been removed by the author.
ReplyDeletehow are newer languages like swift addressing this? like described here: https://www.andrewcbancroft.com/2015/01/06/immutable-types-changing-state-swift/ . iow, what is the java equivalent to let and var? why would a language like kotlin or swift have it?
ReplyDeleteThe difference is, java is "Explicit".
DeleteSo no "real" difference, other than the security model enforces explicit types before will run functions on them.
see:
http://www.securingjava.com/chapter-two/chapter-two-10.html
If you look at the code I posted above, it is possible to recreate the "var" declaration very easily already to do pretty much anything you need.
But such code would never be acceptable in the kind of environments Java is mainly used in.
@Mark:
DeleteYou say that Java is Explicit, so why do your own code examples avoid any explicit types by avoiding Generics?
Why do you confuse type inference with type Object?
How can you say that functional languages, which seems to include Scala in your case, are not enterprise ready (not "secure") when articles I read and job offers I get seem to show the opposite?
It seems to me you never have seriously used anything beside Java, and even Java's type system you haven't used to "secure" your code.
Your arguments seem to fully lack any understanding of types and type systems.
That's not a good basis to discuss type inference in my opinion.
This comment has been removed by the author.
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteLuv it!
ReplyDeleteJava 8:
final BiFunction<Integer, Integer, Integer> sum = (a, b) -> a + b;
Java 9:
val sum = (Integer a, Integer b) -> a + b;
Concise and safe.
PS: Blogspot comment formatting is a pain in the...
Note to myself: Most probably this will not be possible because the compiler can't figure out the concrete functional interface. The upper type bound will be s.th. like Serializble or Object.
DeleteMmhhh...
It would be nice if it could be a free function that is applicable to any location where it matches a specific functional interface.
DeleteYep. That is where "Java is not a Functional language" sadly becomes true.
DeleteJava has a wonderful JVM. But here Java's wonderfulness stops.
Just to say thank you for all the comments. It is clear that this is a divisive issue. While I am not a fan of the introduction of "var", there are definitely positives as well as negatives. My concern is to ensure that the change fits into Java, which is a language with a long history. While I happily accept that in an ideal world the default for local variables would be "final" and non-null, it is also the case that backwards compatibility prevents such a change.
ReplyDeleteBackwards compatibility is just an alibi. All you need is a way of marking the code as Java 9+ directly in the code and then you can use the new syntax. Then the compiler could be fed with both old and new code without any problem. For humans, there'd still some mental strain when switching, but the IDE could help here.
Deletefinal var is an oxymoron
ReplyDeleteI see your point; I would favor an explicit reversed type name (perhaps "local", or "ref") paired with the existing keyword "final" with the reversed word being optional when final is present. The phrase, say, "ref d = 9.5" resolves to "double d = 9.5" and "final a" is synonymous to, and favored over, say, "final local a" or "final ref a".
ReplyDeleteWhat is Colebourne's objection to type inference?
ReplyDeleteIMO, type inference is great. The big reason to not change is legacy considerations. Scala's model is best for Java if you don't consider legacy issues.
I would vote for Rust language constructs which are:
ReplyDelete- "let" for constant fields,
- "let mut" for variable fields,
That promotes immutability (because it requires more typing to get mutable field). Current Java syntax discourages immutability as we must add "final" keyword to enforce it.
I think "let" and "mut" should have advantage over "val" and "var" as "val" and "var" should probably be more often used already as identifiers in source code. Because of that, making "let" and "mut" keywords should require less source code adjustments than by making "val" and "var" keywords.
C# uses var
ReplyDeleteC++ uses auto
both works fine :)
and then there is Scala..is this the same thing?
ReplyDeletehttps://www.stackchief.com/tutorials/Scala%20Tutorial%3A%20var%20vs%20val
Project Lombok provides val. See: https://projectlombok.org/features/val
ReplyDeleteThis comment has been removed by a blog administrator.
ReplyDelete