11 ms·
JEP 286: Local-Variable Type Inference
- exabrial 11y agoNo thanks. I'll take the extra keystrokes
- talideon 11y agoAbout time, given how long C# has had local type inference.
- scalesolved 11y agoI hope this gets added to the language, we use Lombok heavily where I work and find it pretty great with it's val class that allows type inference, although it requires an explicit import and can't be used within Lambdas. The website isn't the prettiest but Lombok is a fantastic addition to a Java codebase and massively reduces the amount of boiler plate often associated with Java. A list of Lombok features https://projectlombok.org/features/index.html https://projectlombok.org/features/index.html Java 8 + Lombok + Guava == happy developers (well at least in my case :) ).
- seanjensengrey 11y agoIf you have an opinionated style guide, I would love to read it. Something like this [0] but for Java. [0] https://gist.github.com/seanjensengrey/a08910b0d204b037c2ba https://gist.github.com/seanjensengrey/a08910b0d204b037c2ba
- javaq 11y agoAre there any repos you can point to that make idiomatic use of J8 + Lombok + Guava as an example for people interested?
- biehl 11y agoMy experience is similar, however more like: Groovy === happy developers
- vorg 11y agoApache Groovy used to have the === operator in its earliest versions, but dropped it in favor of using a custom .is() method. The meaning of == is different to its use in Java, catching out many -- "happy" is not the word I'd use.
- mindcrime 11y agoSame here. Groovy rocks my world and is the main reason I've barely even looked at Java 8.
- incepted 11y agoIf Groovy rocks your world, wait until you meet Kotlin...
- skippytheroo 11y agoIf Kotlin rocks your world, wait until you meet the Scala.
- incepted 11y agoI met Scala a few years ago, we had some fun together but she's way too high maintenance.
- vorg 11y agoApache Groovy has some long-standing governance issues, e.g. the groovy-lang.org DNS is owned by a single individual. Other languages such as Kotlin and Scala have more, er, responsible governance.
- skippytheroo 11y agoLombok has always been a hacky set of language extentions. It says a lot about the need for more language features in Java that developers have been willing to resort to using it. Adding val and var to Java will be a big step forward.
- scalesolved 11y agoSure, no language is perfect but I've never ran into problems using Lombok in production. I'd gladly welcome the majority of its features being part of the core language though! :)
- andyfleming 11y agoThis would definitely be a nice language feature to see in Java. It's one (of many) of the reasons I'm attracted to Kotlin (https://kotlinlang.org/ https://kotlinlang.org/).
- dloose 11y agoCeylon (http://ceylon-lang.org http://ceylon-lang.org) has it too! Sorry. I just like Ceylon
- nikolay 11y agoWith all the fuzz behind Kotlin, just because JetBrains, I am surprised that Ceylon has so little awareness! Ceylon, which has great features, multiple compilation targets (can't wait for the LLVM backend), has a great entity backing it (Red Had), and is created by a celebrity (at least in the Java world) developer (Gavin King)!
- ubertaco 11y agoYeah, and it seems like a good project, but some downsides are that it has to support multiple compilation targets (which can split a language into multiple ecosystems), has only one major user (Red Hat), and was created by Gavin King
- nikolay 11y agoRed Hat > JetBrains though - I doubt Kotlin has a much bigger user base. Plus, being created by Gavin King is good, not bad. Also, multiple compilation targets are considered a plus in other languages (like Dart) - why is this bad for Ceylon? Especially when it along with Java it does not rely on native libraries like most of the other languages like Python, Ruby, and Node.js - it can be very useful and you don't need projects such as GWT if you can compile Ceylon to JavaScript directly.
- ubertaco 11y ago
- paramk 11y agoScala ?
- djsumdog 11y agoExactly!
- greydius 11y agoAll we need is higher kinded types and implicits.
- incepted 11y agoHigher Kinded Types, yes, but implicits... Yuck. Scala has definitely proven them as a failed experiment, I hope we will never seem them again in languages going forward.
- gclaramunt 11y agounless, you're proposing a global implicits dictionary a-la Haskell, leave them alone, I much prefer to give up subtyping...
- Others 11y agoI really like Scala. It is a really interesting language, and a productive one for me to program in. However, I agree that implicits are a bad feature. 90% of the confusing bits of Scala are because implicits exist and are, well, implicit.
- acjohnson55 11y agoImplicits are tricky, but they are the best way I know of to solve the problems they do. Other languages (JavaScript, Swift, etc.) have essentially open classes, where attachment of additional functionality to a type impacts a program globally. Implicits make it much easier to scope these extensions. They are also quite useful for wiring up context (take Akka's ActorSystem, for example) at the declaration level, so that the bodies of your classes and functions only explicitly talk about your domain objects, rather than framework machinery. They're also a big part of the power behind projects like Shapeless, which are quite useful for scrapping boilerplate. Most controversially, they are also used to implement implicit type conversions. Modern idiomatic Scala discourages this, but it can sometimes be helpful.
- vivin 11y agoThis is pretty nice. Hope it goes through. It's about time that we had local-variable inference in Java. It does mean that the diamond can't be used this way: var list = new ArrayList<>(); There is no way to infer the type of the generic parameter. So we will go back to doing: var list = new ArrayList<String>(); Which isn't a big deal IMO because the generic parameters had to be specified on the LHS anyway to use the diamond. You also end up using fewer characters in general with var even without being able to use the diamond. Regarding val vs let, I prefer let simply because it's harder to accidentally type let vs typing var instead of val (or vice versa).
- namelezz 11y agoI hope this gets rejected. The given examples are too ideal as they are all using familiar Java standard APIs. I doubt if it's a good idea in practice since you can end up with unreadable code when integrating with third party APIs.
- msbarnett 11y ago> I doubt if it's a good idea in practice since you can end up with unreadable code when integrating with third party APIs. This works perfectly fine in practice as can be seen using comparable constructs in C#, C++, and many other mainstream languages. If anything it's more readable, since your code isn't littered with redundant type info.
- namelezz 11y ago> If anything it's more readable, since your code isn't littered with redundant type info. I fail to see the redundant type info. Example 1: int maxWeight = blocks.stream() .filter(b -> b.getColor() == BLUE) .mapToInt(Block::getWeight) .max(); "int" is not redundant type info here. Example 2: List<String> list = new ArrayList<>(); // (1) var list = new ArrayList<String>(); // (2) Many would say List<String> in (1) is redundant but I would argue otherwise. The intention of List<String> in (1) is to reference to the underline ArrayList through List interface. (1) is trying to encourage programming to an interface while (2) just completely destroys the practice by inferring the type for list variable to be ArrayList<String>. That means subsequent method invocations after (2) can be methods from ArrayList not List.
- emmanueloga_ 11y agoI wonder if this JEP draw any inspiration of http://www.eclipse.org/xtend/ http://www.eclipse.org/xtend/. For those new to xtend, think of it as xtend is to java like coffeescript is to javascript. I wish most of the xtend enhancements were integrated to java asap!
- betimsl 11y agoCame to write this here. Xtend is amazing for these things.
- merb 11y agovar + val would be great.
- nikolay 11y agoYeah, let's spread the nonsense further! There are constants and variables; values are something else. Just because "val" is a short abbreviation everybody gets, it doesn't mean we should abuse it!
- usrusr 11y agoMaybe i'm just weird, but to me, when i hear the word "constant" i expect something that is nailed down at compile time. final int chosenByFairDiceRoll = 4; // a constant final long millis = System.currentTimeMillis(); // not a constant When you say "values are something else", is it that you would consider chosenByFairDiceRoll a value, but not millis? I guess that you might have had more exposure to languages that use "const" instead of "final" than me...
- Others 11y agoI disagree with that sentiment. Constant to me implies decided at compile time. The reason we should use "val" is because it is a short abbreviation everybody gets. It also has symmetry with "var," as "value" and "variable" are both adjectives, whereas "let" is a verb.
- Retra 11y agoI've been programming for 15 years and I'd have no clue what the difference between val and var is without looking it up. So I guess your definition of 'everybody' is JavaScript programmers? And every time I see 'var', I cringe because I don't know if they mean variable or variant. But 'val' is just usless. Variables evaluate to values, constants evaluate to values, expressions are values, first-class functions are values... Everything is val.
- ygra 11y agoI'd find var and val way too easy to confuse. Added to the fact that Java has "effectively final" variables already there should be no need to distinguish here. If anything I'd probably be in favour of "var" and "final var", which would follow existing syntax in the language.
- linuxhansl 11y agoHmm... I agree it looks nicer. Who's typing Java code all by hand these days, though? There various IDEs that save me all the typing. It's also nice to be able to go the declaration of a variable to see exactly what type it is - that's mostly for code not written by myself, or old code that I do not remember. For local variable that's fine (I hope we won't infer types this way for method parameters), so I guess I like it there.
- breischl 11y ago>>I hope we won't infer types this way for method parameters No, it doesn't. From TFA: "This treatment would be restricted to local variables with initializers, indexes in the enhanced for-loop, and locals declared in a traditional for-loop; it would not be available for method formals, constructor formals, method return types, fields, catch formals, or any other kind of variable declaration." Which is pretty much how C# does it. I gather that it's common for functional languages to infer pretty much everything for you most of the time, which I think would actually be nice. But presumably that's either difficult or impossible in Java.
- the_af 11y ago> Who's typing Java code all by hand these days, though? There various IDEs that save me all the typing. Reducing boilerplate mostly helps with reading code, not with writing it.
- agumonkey 11y agoIt does, my code and trail of thought is significantly different when switching to coffeescript from javascript.
- usrusr 11y ago> Who's typing Java code all by hand these days, though? > There various IDEs that save me all the typing. Some truth in that, it should be safe enough to assume that the lightweight editor crowd has long self-selected out of java. I often do write-time type inference by declaring anything as an int and then, at the end of the line, pressing whatever magic key that makes the IDE rewrite it to the actual type so that it compiles. One of the syntax options in the JEP is "final name = RHS;". When i first saw that i could not understand why anybody in their right mind would even consider a partial solution like that. But now that i wrote about write-time type inference, it starts getting more and more attractive: A tiny nudge towards immutability, natural "write-time type inference" that is correct until the first nonfinal access is written (IDEs already offer a "make nonfinal?" fix in that case) and nonfinal identifiers will often be a broader type than the RHS assignment anyway.
- phaed 11y agoOh god yes.
- djsumdog 11y agoHey look, it's something else that's been implemented in almost every other JVM language that hasn't made it into Java yet.
- pdpi 11y agoBeing conservative about what you add to the language is a feature, not a bug. Not all languages need to be on the cutting edge (even if I personally prefer the languages that are)
- dloose 11y agoSee Brian Goetz's talk on language stewardship (https://www.youtube.com/watch?v=2y5Pv4yN0b0 https://www.youtube.com/watch?v=2y5Pv4yN0b0). I'm sure nobody wants to add new and interesting features to Java more than the people who work on the language every damn day, but they've made a strong commitment to the community to not break existing code.
- ygra 11y agoC# shows pretty compellingly that adding features does not have to break existing code. For example, you can use every keyword added after 1.0 as identifier, too.
- SideburnsOfDoom 11y agoBut it can make things more complex too. e.g. I recently learned that the main reason that asynchronous C# methods have to be declared "async" is so that the compiler knows that in the method body, "await" is a keyword. Without this backward compatibility requirement, it could be inferred from the return type + the presence of 1 or more "await" keywords.
- mmatants 11y agoI for one actually prefer to put a different type on the variable than the implementation. I.e. in the given case, I would actually use: `List<String> a = new ArrayList<String>();` I know that for some things it is convenient, but I appreciate the reminder to treat interface and implementation as distinct concepts.
- involans 11y agoFor local variables within the body of a method it doesn't really matter. As long as the method signature is expressed in interfaces, you should be able to use whatever implementations you want within the method body.
- usrusr 11y agoExcept when you add final, then there is little reason to have the less specific type. But i see where you come from, it feels a bit sloppy to not document the intention that the variable _could_ be any kind of list, even though it happens to be an ArrayList. Not "this may lead to nasty bugs"-sloppy, but a slight case of "this won't win any beauty contests"-sloppy.
- wtetzner 11y agoThis is for local variables, though. You can use var as the return type of a method. If your method bodies are so large that you need to be coding to interfaces within them (as opposed to just setting the return type of your method to the interface), the you've got other problems.
- gabriele 11y agoI expect this breaking a few things in fields injection (a la Spring @Autowired[1]) if implemented. [1] https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/beans.html#beans-autowired-annotation https://docs.spring.io/spring-framework/docs/current/spring-...
- ygra 11y agoHow would type inference for local variables mess with fields?
- gabriele 11y agoaccording to Spring's documentation[1]: @Autowired is fundamentally about type-driven injection If you replace: @Autowired FooDao fooDao; with something like: @Autowired var fooDao; I'm pretty sure type-driven injection breaks. [1] https://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-autowired-annotation-qualifiers https://docs.spring.io/spring/docs/current/spring-framework-...
- ubertaco 11y agoYeah, but that's a case where "var" is probably the wrong choice anyways, because of the non-obvious "human type resolution" -- i.e. if I'm a human reading this code, I can't obviously tell the type FooDao, where in simple cases like var path = Paths.get("/foo/bar/bonk") I can.
- radq 11y agoThe proposal only applies to local variables with non-null initializers. I'm pretty sure you can't autowire local variables with Spring, and they don't have initializers anyway.
- TheCoelacanth 11y agovar isn't a dynamic type. var is a compiler-inferred static type. `var fooDao;` will refuse to compile because the compiler can't infer the type. `var fooDao = new FooDao()` will still have the type FooDao for fooDao, it is just inferred by the compiler instead of being explicitly declared by the programmer.
- mythz 11y agoCool, this will help Java from looking so bad: https://gist.github.com/mythz/7e263820332a0fcea766 https://gist.github.com/mythz/7e263820332a0fcea766 From Java LINQ Examples: https://github.com/mythz/java-linq-examples https://github.com/mythz/java-linq-examples
- kuschku 11y agoThat code is a wrong equivalence — Java's lambdas make that code already a lot more readable, but somehow weren't used in that example.
- plesner 11y agoIn their list of risks there's one missing: it makes changing the return type of a method to a subclass a subtly breaking change. Say some api defines a method, Collection<String> getNames() { ... } and in your code you do var names = getNames(); if (...) names = Collections.emptySet(); Now, if the api later changes getNames() to be List<String> getNames() { ... } your code breaks. That's one of the advantages of only allowing this on final variables (besides reusing an existing keyword): it means this can't happen. Of course you already have a problem if the class has subclasses but I would argue that this is more subtle and problematic.
- wvenable 11y agoI think in practice this would be pretty rare. At least coming from a C# background it doesn't seem to be an issue I've ever encountered.
- plesner 11y agoIt's possible that it's more a theoretical than a practical problem, I would hope so. But it does seem to me like fundamentally a problematic property of a type system that having more accurate types can break your program. It's the static type equivalent of breaking the Liskov substitution principle.
- wvenable 11y agoIf a library author makes such a fundamental change their public API by making a method return more specific, I might actually want to know about it. I don't find it particularly problematic since it seems like code smell for that sort of change to happen in the first place.
- skippytheroo 11y agoIt will be caught as a compiler error. Since you would typically have the method signature declare that it returns the most general type it should be a non-issue. It's really no different from breaking code today by changing a method signature in an API.
- freekh 11y agoI hope this goes through! A while back, I was trying to explain in what ways Scala is more typesafe than Java for a friend (which was one argument to why I prefer Scala so much), and ended up realizing how important type inference is in this regard. The reason was this: quite often type signatures correctly modelling a domain ends up being pretty hard to read. In a good and proper API, this happens in particular whenever something is composable and is, in fact, composed (if one can say that). I suppose one can say that, for Scala, it took a bit of time before people figured out how to do this properly, rather than just hacking the type system, but I feel that the ecosystem is more or less there now... YMMV though... As an example: in something like Slick (a functional-relational mapper) in Scala you end up with monads to model your SQL query. One advantage this has is compile errors whenever you're doing something wrong (i.e. more typesafe), but the types that a SQL query representation ends up with will necessarily be pretty hard to read and practically impossible to write (you could have a Query of a long chain of other types for example if you're querying multiple columns). In this example, somebody writing the query might not care about the type of the query. They will care about what the query will end up returning when executed though. I suppose it will lead to trouble when you can't read the type signatures well enough and try to figure out the compiler error, but I reckon it's better to have an error, than to see it fail runtime (at least in my world :). It's easier and safer to do maintenance too, since the compiler and IDEs can know how things should work. In any case, you could conclude that, in a statically compiled language where you do not have type inference, you'll end up trading in preciseness in the model of the domain, in order to have readable code from the callsite. In turn, this leads to less typesafe code. One challenge that Java will have even when implementing this though, is how to move the entire ecosystem to something that is indeed more typesafe. This only works if the APIs are doing this right. EDIT: typos, language and less parens
- incepted 11y ago> A while back, I was trying to explain in what ways Scala is more typesafe than Java for a friend (which was one argument to why I prefer Scala so much), and ended up realizing how important type inference is in this regard. Type inference has absolutely nothing to do with type safety. Programming languages don't become more or less statically type safe depending on whether they support type inference. Type inference only enables to omit type annotations in certain parts of your code. Your values are just as typed as if you had used that type annotation. As for the original point you were trying to make, I would say Scala is no more type safe than Java. They are about on par in how they allow unsafe expressions to type check. Scala's type system is certainly richer than Java's, but that's a separate point (and maybe the one you were trying to make). > In any case, you could conclude that, in a statically compiled language where you do not have type inference, you'll end up trading in preciseness in the model of the domain, in order to have readable code from the callsite. In turn, this leads to less typesafe code. Absolutely not. Omitting a type in your source doesn't remove the type from that variable. The code is exactly as typed with that type annotation as it is without.
- vbezhenar 11y agoJava loses its explicitness with each release. And it's still much worse as a language than Scala, Kotlin, Groovy, Ceylon (and probably always will be behind). I don't see much value in those improvements. If one wants a better Java, he can use it right now. What Java needs is JVM improvements, like value types or full support for bytecode hot reload. Java 1.4 was very minimalistic and beautiful language. I liked it that way.
- vorg 11y ago> it's still much worse as a language than Scala, Kotlin, Groovy, Ceylon Some of those languages are better than each other, and they are much worse languages than Clojure, another JVM-hosted language you ignored.
- vbezhenar 11y agoClojure is very different language, and I don't know it well, so I didn't include it. Of course it's not a closed list.
- PantaloonFlames 11y agoWelcome to 2007? C# added implicitly typed local variables (and the var statement) to the language 9 years ago. https://msdn.microsoft.com/en-us/library/bb308966.aspx https://msdn.microsoft.com/en-us/library/bb308966.aspx
- jonsterling 11y agoWelcome to 1972, actually! https://en.wikipedia.org/wiki/Logic_for_Computable_Functions https://en.wikipedia.org/wiki/Logic_for_Computable_Functions
- pgroves 11y agoI really want this. I gave up on Ocaml because it just isn't a big enough ecosystem but everything else seems like I'm making the wrong things explicit in the code.
- jkot 11y agoI hope they will give it second though. In Java 'var' or 'val' are not reserved keywords. It was difficult to migrate existing code when 'enum' was introduced. 'const' is reserved but nothing for variable, perhaps 'new' or some symbols.
- ygra 11y agoThey will be made into reserved type names. Since classes with those names violate naming conventions anyway they should be quite rare.
- stygiansonic 11y agoThe approach taken to preserve backwards compatibility with existing code that already uses `var` as an identifier is interesting: "The identifier var will not be made into a keyword; instead it will be a reserved type name. This means that code that uses var as a variable, method, or package name will not be affected; code that uses var as a class or interface name will be affected (but these names violate the naming conventions.)" I didn't know there were such things as "reserved type names", but I'm guessing `var` will be treated sort of like `String` or `Object` (always available without an explicit import) and maybe it'll be a class in `java.lang`? Seems like a much "nicer" approach than when Enum types were introduced with the `enum` keyword, but I guess that was slightly different.
- TazeTSchnitzel 11y agoPHP recently did the same thing with PHP 7, which introduced type declarations for the scalar types. This meant we needed to reserve `int`, `float`, `string` and `bool`. To minimise backwards-compatibility breakage, we only reserved these as class/interface/trait names, and not in other contexts. And it seems we were right to reduce the scope of it. PHP 7 prohibiting "String" as a class name ended up being a significant BC break affecting several projects. I imagine it might have been worse still if `string` was a reserved word.
- acjohnson55 11y agoThe reaction here is indicative of why I'm starting to consider whether maybe it's best that Java stays Java. Sure, I'd personally be really annoyed typing super redundant type declarations everywhere. But then again, I wouldn't have to, because I'd simply use Scala, because it's more expressive. But a lot of people clearly love good old verbose Java. Java has been super slow to adopt things that are more or less the norm in other popular languages. Why bother at this point? Isn't Kotlin a pretty good sugared-up Java, anyway? Lightbend (caretakers of Scala, Play Framework, Akka, Spark, Slick, SBT, and others) wisely announced their dedication to both Scala and Java. It's caused a big stir in the community, but it kind of seems like that should make everybody happy. They're two ecosystems geared to serious software, built on a solid platform, but with very different constituencies. Lightbend realized there's no point in pressuring people to adopt Scala. People will do it on their own, if they want to. But with strong support of both languages, they can address a very broad swath of the development world.
- skippytheroo 11y agoThe reaction from some reminds me that some Java programmers will always resist change. Java's current feature set is the one true way (tm) and any features other languages have are bad, that is until they are officially added to Java and are then suddenly considered part of the one true way (tm) and further evidence of the language designers' wisdom.
- zZorgz 11y agoHaving the option to use type inference in this specific use case is nice. But I'm glad it's just for initializers. After playing with Scala, I've found out I don't love type inference as much as I thought I did. In Scala, the compiler can infer return types of named procedures for example, but I've always found omitting these makes my code harder to read, having to read the body (an implementation detail) to see what it may be returning. It would be even worse if types were optional for parameters (ala Haskell). Other modern languages (ala Rust) have come to realization that this is a bad idea. The same even applies to having the compiler infer types from local variables to a lesser extent. A lot of my code goes through transformations and chains, and sometimes it's not obvious what the resulting type is (and what the code is doing) if the type is not specified. Even looking at the simple example mentioned from the article in isolation: var stream = list.stream(); I don't know what type stream is. Sure, I can make an educated guess that it's some kind of Stream, but then knowing it's a parameterized, and then knowing what kind of type it takes is even more challenging. I would have to look at the right hand side (again, an implementation detail), or may have to traverse up even further (eg: looking up how `list` is derived in this case) to figure out for sure. Or worse yet, look up documentation. Imagine if the right hand side was composed by calling a series of procedures, then you have to traverse all the way to the right to validate the type. In the end, you have a mental burden. The same issue applies with calling functions and assiging their result to a local variable you're initializing. I'm happy to see type inference is just added for initializers. Whilst I haven't found writing 'Foo foo = new Foo()' that common in functional code, I see that being prevalent in Java at least. On the flip side though, if your language or use case (C++?) makes code harder to understand rather than easier by specifying types, then you may be wishing you had type inference :)
- dllthomas 11y ago> It would be even worse if types were optional for parameters (ala Haskell). The Haskell community seems pretty well agreed that top level declarations should have type annotations (arguments and return values) in code that's going to be maintained. With -Wall, GHC will even give you warnings about top level declarations without types. No reason to require it for quick (~5 min) experimental hackary or one-off scripting - in that case, add it if it helps and omit it if it doesn't, and the ability to ask what the compiler thinks the type is can come in handy as well.
- nsxwolf 11y agoI've never liked this language feature very much. I'm the one that's doing the inference when I read the code.
- wmu 11y agoI totally agree, type inference speed writing a code, nothing more. For easy cases reading such code is OK (var path = "/usr/bin/whatever" - obvious), but with a more complex code it becomes awful. I'm a C++ programmer, and quite often I have to dig through dozens of headers to find out what this magic "auto" really means.
- icebraining 11y agoThat's because C++ combines type inference with a gnarly compilation process. In a language like Java, editors will support it and you'll just be able to "mouse over" (or press a key combo in Vim/Emacs) and it'll tell you the inferred type.
- ryenus 11y agoVote here: https://www.surveymonkey.com/r/KGPTHCG https://www.surveymonkey.com/r/KGPTHCG This survey will remain open for one week, from Mar 9 to Mar 16.