MMS • Karsten Silz James Ward
Article originally posted on InfoQ. Visit InfoQ
Key Takeaways
- Java is still a great language, but Kotlin is a faster-developing, incremental alternative, while Scala takes Functional Programming to some extremes.
- James prefers languages that let him write more correct code through a high level of validation at compile time.
- Through Scala, James found programming paradigms and experiences that have altered his way of thinking.
- Default mutability in Java is a “trillion-dollar mistake” because it makes it hard to reason about what the code does.
- Project Loom’s approach is a game-changer because it removes the cognitive overload of reactive programming.
James Ward is a Java Champion and Kotlin Product Manager at Google. He hosts the “Happy Path Programming” podcast with Bruce “Thinking in Java” Eckel. In one episode, Eckel spoke of “people who are still trapped in the Java world.” Ward agreed and called default mutability in Java the “trillion-dollar mistake” (referencing the “billion-dollar mistake” of NullPointerExceptions
). InfoQ got curious about this Java champions’ view on Java and asked Ward some questions. Here are the answers.
InfoQ: What is the role of the Kotlin Product Manager at Google? What are your day-to-day responsibilities?
Ward: There are two sides to the Kotlin PM job. I work with our Android teams and JetBrains on Kotlin language improvements and growth. I also work with many engineering teams within Google to help make their server-side and Android migrations from Java to Kotlin successful.
InfoQ: What is the state of JVM languages in 2022?
Ward: I began using the Java programming language 25 years ago and think it is still a great language. But I’ve also been able to work with more modern JVM languages over the past ten years, including Scala and Kotlin. Scala is great for developers wanting to take Functional Programming to some extremes. Kotlin is more of an incremental step for existing Java developers having good support for some Functional paradigms like immutability and sum types but lacking some of the “Monadic” features that Scala has. Both Kotlin and Scala have great interoperability with Java, enabling ecosystem sharing. JVM developers have many options for great languages and a lot of tooling overlap (build tools, IDEs, production/introspection tools, etc.). It is great that on the JVM, in one large ecosystem, there is such a spectrum of language options.
InfoQ: How much JVM back-end development happens in Kotlin these days? And how do you think Kotlin could become more popular there?
Ward: Overall, the Kotlin share of JVM servers is fairly small, but it is growing quickly. Google, for example, has seen significant growth in the use of Kotlin for server-side development. Developers who’ve either switched from Java or come from other languages report they are very satisfied with the experience. Null safety, coroutines, and expressiveness are often noted as important reasons why Kotlin is more productive and fun to work with.
Kotlin will definitely continue to grow on the server-side. Spring, Quarkus, and Micronaut have done quite a bit of work to make their Kotlin experiences great (such as coroutine interoperability for Reactive). Enterprises generally move pretty slowly with new technologies. Still, for many the move to Kotlin (on the JVM) is a much less risky and disruptive change than moving to Rust (for example). Also, Kotlin’s interoperability with Java helps code migrations to be incremental instead of rewrites. Many teams I’ve worked with just add new code in Kotlin to an existing Java codebase.
InfoQ: How do the JVM languages stack up against other programming languages, especially in the cloud? Python and JavaScript are more popular than Java in Google searches and have more questions on Stack Overflow.
Ward: If I were designing a programming language, I’d aim to have fewer searches and questions asked about my language. 😉 Having been a programmer for over 30 years, I tend more towards languages that enable me to write more “correct” code that is testable and reusable. I don’t like surprises in production, and I want to be able to refactor without fear. Having a compiler that can perform a high level of validation on my program is an essential feature. Sure I might not be able to write raw code as fast as others, but I do write code that is pretty unlikely to have bugs in production. If you consider fixing production bugs as part of the development cycle, then using modern languages on the JVM likely provides the highest productivity possible for many problem domains.
InfoQ: GraalVM produces native Java applications that start faster and use less memory. How will this affect the competitive position of JVM languages in the cloud?
Ward: Startup and memory overhead have definitely hindered the adoption of JVM technologies in some problem spaces (serverless, CLIs, Kubernetes operators, etc.). GraalVM Native Image, Kotlin/Native, and Scala Native help take these languages to places where typically interpreted or native languages used to be a better fit. Now we can have our cake (fast startup and minimal memory overhead) and eat it too (modern high-level languages). I recently created a server with the Kotlin Ktor library, which I can run on the JVM or compile to native with both Kotlin/Native and GraalVM Native Image. In the native case, the startup time was about 2 ms, the memory usage was 11 MB, and the binary was compacted down to 700 KB. For many use cases, we no longer need to make tradeoffs between native and modern/high-level languages.
InfoQ: What makes Scala so appealing to you?
Ward: Scala has a long learning curve. After over ten years with the language, I still feel like a novice. Which is great for me because I love learning new programming languages and enjoy the challenge. I also have really bought into many of the principles of Functional Programming but have not yet followed those all the way to Haskell, so Scala is a good place to be somewhat comfortable with JVM-based FP. I’m currently writing a book with Bruce Eckel and Bill Frasure about Effect Oriented Programming in Scala 3 and ZIO 2. Functional Effects represent a concept that makes a significant difference to the quality of software we create but isn’t well supported yet in Java or Kotlin. There are many reasons to choose Java or Kotlin, but concepts like Effects are not on that list.
InfoQ: For which applications or problems is Scala a perfect fit? Where is it not?
Ward: Many factors determine technology fit. I’ve worked on projects recently where team structure implied that Java and Spring Boot were the best fit for the environment. One of the most significant factors to “fit” is the technology the team wants to use. I think this aligns with my Kotlin PM job goals which revolve around helping make Kotlin a technology that developers want to use.
InfoQ: JetBrains claims Kotlin is a “better Java,” but Java is still 5-12 times as popular. Where do you see Kotlin’s role today? And what will its role be in the future?
Ward: The Java language has evolved over time. But as the language architect (Brian Goetz) describes — it has a “last mover advantage,” which in many cases is the right choice. If startups live by the slogan “move fast and break things,” then enterprises live by the slogan “move slowly and break nothing,” which is pretty consistent with how the Java language has evolved over the past 20 years or so. For me, I like to move faster than typical enterprise organizations enable (due to compliance, security, regulatory, and other reasons). So yeah, Kotlin is in some ways a “better Java,” but “better” for me may not be “better” for everyone, and that is OK. The JVM and Android support both Java and Kotlin — and that is a good thing.
InfoQ: In episode 51 of your Happy Path Programming podcast, Bruce Eckel spoke of “people who are still trapped in the Java world” (around 33:15). You agreed. Please explain to our readers why you and Bruce feel this way.
Ward: 25 years ago, I wrote my Java like I wrote my Perl. Bruce’s “Thinking in Java” transformed how I thought about programming. Now both Bruce and I have found programming paradigms and experiences that have had the same effect, totally altering the way we think about things. Bruce and I have not experienced these disruptions through Java (the language) but through other languages. I believe what Bruce and I were highlighting in that episode was not a knock against Java (the language) but a hope that programmers continually learn and find ways to grow, just as both Bruce and I have.
InfoQ: As described by Tony Hoare, NullPointerExceptions
are the “billion-dollar mistake.” Null safety in a language is the fix. Kotlin has it, and Dart and Swift even have sound null safety. Java doesn’t have it and doesn’t seem to get null safety anytime soon. Why do you think that is?
Ward: In Java, EVERYTHING that is not a primitive value is nullable. And it would require a massive overhaul of the whole language and standard library to change that. Many modern languages have a foundational principle that nullability should be expressed through the type system. It is just very hard or impossible to bolt on later. As described earlier, I aim to write programs that are more verifiably correct at compile time, and explicit nullability is one way I do that. One of the reasons I don’t use the Java language much anymore is because expressing nullability in a compiler-verified way is tough.
InfoQ: You said that adding null safety is “very hard or impossible to bolt on later.” Google’s Dart accomplished this by adding null safety for applications and libraries seven years after version 1.0. 😉 Anyhow, what’s your advice to Java developers who want to have fewer NullPointerExceptions
?
Ward: The hard part isn’t the language feature. It is all the APIs. According to the type system, everything in the Java standard library and most everything in the Java library ecosystem is nullable. For null safety to be useful and not gigantically annoying to deal with, all underlying types must correctly express their nullability. This is the change that is very hard or impossible to make.
InfoQ: In the same “Happy Path Programming” episode, you called default mutability in Java the “trillion-dollar mistake” (around 35:05). Please elaborate on why you think that is.
Ward: I’ve been bitten too many times with production issues where it was very hard to figure out the cause because I was unable to “reason” about the code in question. You see this when people post the “what does this code do” kind of puzzler on Twitter. Most of the time, it is a puzzler because the mutability makes it so my simple brain can’t reason about what is happening. You never see people posting the same kinds of challenges in a purely immutable form because immutable values and pure functions are something my brain can comprehend. I’m certain that the more of our programs can be pure functions and values, the fewer bugs there will be in what we build.
InfoQ: How much do you think tool support (such as IDEs and build tools) matters for the success of a programming language?
Ward: I used to write a lot of code without the help of an IDE (vim — fight me, please), but now the IDE is an essential part of my productivity. One reason I love programming languages with great type systems is that the IDE provides much better hints as I write code. When I have to write code in dynamic languages, I wonder how anyone ever does anything without a million reference API lookups because I can’t do anything without my IDE dot-completing all the options.
InfoQ: Talking about tools: Visual Studio Code had 14 million users in February 2021 and was the second-most loved IDE in Stack Overflow’s “2022 Developer Survey” (neovim was number one). Let’s assume that Visual Studio Code becomes the default free IDE for all developers, supporting all relevant programming languages and frameworks. How would that change software development?
Ward: VS Code is a great tool and, for many developers, has been a huge step forward from “Sublime Text,” vim, or emacs. But for me, it is still significantly less helpful than IntelliJ (for JVM stuff), especially when it comes to refactoring. So I don’t use it much, but I get that it very well may be the best code editor that developers have used (assuming they haven’t used all of them).
InfoQ: Compilers reveal code errors. Static analyzers, such as Error Prone, Spotbugs, or PMD, show even more errors, including the dreaded NullPointerExceptions
. Why aren’t these static analyzers more widely used then?
Ward: Generally, I like to keep my toolchain as condensed as possible. Whether for performance, simplicity, or collaborative reasons, I prefer to put as much validation logic as possible into something the compiler can validate (i.e., the type system). To me, linters and static code analysis tools are a sign of something that should just be validated in the compiler. Still, likely, there are language constraints preventing that. These tools are good for improving code quality but also a strong signal to language designers of what they should be trying to move from meta-programming to just programming.
InfoQ: You said you “prefer to put as much validation logic as possible into something the compiler can validate.” The Java compiler doesn’t validate null safety, empty else
branches, and such. But static analyzers like Google’s Error Prone do. How do you see the benefits of adding these analyzers to Java versus the downsides of complicating your toolchain?
Ward: Linters and other static code analysis tools express limitations with the type system and compiler checks. These limitations will always exist, so the tools won’t go away anytime soon. But hopefully, they help programming models and compilers to evolve, covering more of the possible foot guns over time.
InfoQ: Google’s cross-platform UI framework Flutter takes less than a second to compile a change and update the application. Why is compiling and updating JVM applications still so slow by comparison?
Ward: The more a compiler does to validate the correctness of something, the longer it will take. I don’t know any way around that. I can do zero-compilation on something, run it in production, then get runtime errors as a result. That is not the way I want to develop software. So to me, judgments of compile time have to be balanced with compiler value. However, I do often run Java, Kotlin, and Scala compilers incrementally with hot-reload in under a second (thank you, good caching). This debate needs to shift to “how long does it take to get to correct or bug-free” instead of “how long does it take to get something with an indeterminate amount of broken to production.”
InfoQ: In my Spring Boot project, frequent class reloading failures negate my fast compilation speed. And with regards to your “get something with an indeterminate amount of broken to production” comment: I think compilation complexity for Dart (the language in Flutter) may be in the ballpark of Java. Still, Flutter recompiles and redeploys on mobile in one second most of the time. Most Java projects don’t. Now Flutter owns its whole toolchain (language, compiler, runtime, framework, and build tool). Java doesn’t (e.g., build tool and application framework). For developer productivity, how important is it that JVM languages own their whole toolchains?
Ward: Nothing is preventing similar inner-dev cycle times on the JVM from being that fast. A new Android Studio feature called Live Edit almost instantly updates the UI for Jetpack Compose apps, based on a code change, in an emulator, or on a device. Play Framework had sub-second server reloads on the JVM a decade ago, using some fancy classloader tricks. The challenge is mostly around investing the engineering time to make that experience fast and great. But for some reason, that hasn’t been a huge priority in the JVM ecosystem. For server frameworks, Quarkus has done the best job optimizing this, and I’m sure there is more they could still do.
InfoQ: How would you define and measure the success of a programming language? For instance, you could say Scala is successful because it made functional programming more mainstream. You could also argue that Scala isn’t successful anymore because it lost the #2 JVM language spot to Kotlin.
Ward: Goals matter, and everyone has different goals. For me, it is about value alignment. I really appreciate that the Flix programming language wrote down its goals/principles.
Flix is an incredibly successful programming language because it has done an amazing job executing its goals. If Flix set a goal to have 10 million active developers, they’d definitely be failing on that one (but I’d still like it because I agree with the principles of the language). Liking a language is different from the success of a language. As a Kotlin PM, one of my goals for the language is to make it easier for developers to build correct software (i.e., fewer production bugs). The language has already been shown to reduce Android app crashes by 20%, which is a big success. I’d like to take this further and continue to help reduce app and server-side errors with language and tooling improvements.
InfoQ: The history of software development is a history of increased levels of abstractions. But innovations like object-orientation and functional programming are more than 50 years old. How do you think the abstraction level has increased in the last 20 years? And how do you see it rising in the next 20 years?
Ward: Until recently, many of the ideas from Functional Programming were siloed into technologies for math nerds (of which I aspire to be someday). Now thanks to Scala (and others), we are beginning to see a fusion of OO and FP that makes FP accessible to the masses who may not be math nerds. This fusion will continue to play out for a while, helping to make our code more testable and reusable. Kotlin is a great example of that, being a bridge for many OO Java developers into “lite-FP,” which doesn’t require a degree in Category Theory. The next phase of this transition will include embracing the idea of “Effects” (separating pure functions from the small parts that talk to the external world / aren’t referentially transparent). Many new programming languages already have this concept built-in: Flix, Unison, Roc, etc. Beyond effects, one concept we will likely see emerge is something like Datalog — a query language built into the general purpose language. I first saw this idea with Linq, then with Flix. Queries are a pretty universal need, whether for databases, lenses (updating immutable data structures), GraphQL, etc. So having an integrated and compiler-verified way to write queries is a significant advantage.
InfoQ: Which programming language has evolved the best?
Ward: This definitely depends on the definition of “best.” If we consider this from a purely academic perspective, I think by many orders of magnitude, Scala has been the recipient of more Ph.D. research than any language I know. Many of the Scala language features end up in other languages, which is great for everyone. Python has done an amazing job of being a generally approachable language. I heard that many data-oriented professionals can’t solve most of the typical programming challenges but can write the Python code that represents a complex mathematical algorithm or processes a massive data set using libraries like Pandas, NumPy, etc. Kotlin is a modern language with Java interop and multiplatform capability. So what is “best” depends on many factors.
InfoQ: Which upcoming feature of any JVM language excites you the most?
Ward: On the JVM side, Loom is game-changing. For most Java / JVM developers, “Reactive” has been a good idea but not worth the cognitive and complexity overhead. Kotlin Coroutines enabled a similar idea of zero-cognitive cost for async operations that appear imperative. Yet, for many JVM developers, Reactive will likely remain a “nice-to-have” feature until Loom is available in their organization. Given that timeframe, many developers on the JVM will use concurrency abstractions like Kotlin Coroutines and Scala ZIO Effects on JDK 8 before then. Given the challenges with the Loom timeframe, and the current availability of alternatives, I have to say the upcoming feature I’m most excited about in any JVM language is Scala’s braceless syntax which is half there in Scala 3.0 and may reach completion in Scala 3.3. I love how little visual noise there is in my code relative to the problem I’m solving for. I know it seems silly that just removing the braces can have such an impact. But Python shows us that cognitive overhead may generally be the highest cost in most organizations. The hardest/most costly part of writing a correct program is not the text to bytecode/machine code transformation. It is the cost of correctly representing and reading human ideas in a form that computers can understand. It seems silly, but the braces in most code distract my brain from the human intent of the code.
InfoQ: If you could make one change to each JVM language, what would those changes be?
Ward: Java: There are a lot of changes I’d love to make, and that sounds like an indictment. But it isn’t because on the JVM, you can either choose another language or accept that things move slowly, and that is good. If I had to pick one thing to change, it’d probably be better support for immutability. Default mutability is a recipe for non-deterministic programs.
Kotlin: When I program in Kotlin, the thing I most miss from Scala is a nice syntax for monadic chaining (called “do notation” in Haskell and a for comprehension in Scala). Like Kotlin coroutines, it makes code seem imperative when really it is chained function calls. I have no idea how that kind of thing should be added to Kotlin, but if done right, I think it’d be awesome.
Scala: The hardest thing about Scala is that there are many ways to do roughly the same thing. For example, there are at least three ways in Scala 3 to do something that is basically a Sum Type (sealed, enum, and logical OR). I don’t know how you ever take things away in a programming language. Still, Scala complexity is a problem, and having many ways to do most things is a problem for the language.
InfoQ: COBOL is more than 60 years old and still in active use. Do you think developers will still write new Java applications when Java turns 60 in 2056?
Ward: For sure! Java is a critical part of so many of the systems we use every day. It is not going away, and with slow but progressive enhancements, it continues to improve (unlike COBOL). The larger Java ecosystem (including Kotlin, Scala, Clojure, Groovy, etc.) also continues to grow. As a whole, it is likely the largest developer ecosystem in the world. New JVM languages continue to emerge like Flix, showing that the innovation cycle isn’t stopping anytime soon. Innovative and game-changing technologies like Testcontainers, GraalVM, and Kalix continue to emerge from the Java ecosystem, illustrating the strength to continue growing and improving for another 35 years (at least).
InfoQ: Please share your closing thoughts on JVM languages in 2022.
Ward: It is an exciting time to work with Java, Kotlin, and Scala! The tools and languages enable the highest developer productivity I’ve ever experienced. From phones to servers, Java technologies are behind the vast majority of critical systems we use every day. And for me, it is so nice to get to pick from many different languages on one platform.
InfoQ: James, we thank you for this interview.
Wrap-Up
Ward explained the podcast remarks well: When Eckel spoke of “people who are still trapped in the Java world,” he was referring to developers using what he and James see as old paradigms in Java, such as procedural and object-oriented programming. In contrast, Eckel and Ward have embraced functional programming concepts in Scala that are not available in the Java language. And mutable code makes it harder for Ward to reason about that code and eventually produces more bugs, unlike pure functions and values that are immutable.