Skip to content

Latest commit

 

History

History
99 lines (73 loc) · 6.35 KB

README.md

File metadata and controls

99 lines (73 loc) · 6.35 KB

Java Getting Closer to Scala’s Expressiveness

Java will never be as expressive as Scala. Scala’s feature set allows for writing complete DSLs as well as concise, terse code. That said, Java is getting closer. Since JDK 14 Java has had preview support for “records” which are similar to Scala’s case classes. In future JDKs records will have near feature parity with Scala’s case classes.

The Example

For me, the most expressive feature of Scala is its case classes with pattern matching. Once you’ve coded with this feature you’ll never want to return to the alternatives. This repo shows Java’s progress towards equalling Scala’s case class feature. It’s unlikely that Java will ever completely match Scala but it will get close.

Shown here is a very old interpreter from the Scala examples website. It’s not meant to represent current idiomatic Scala nor is it meant to be a definitive example. However, it’s simple, fits on one page and shows the expressiveness of case classes.

Multiple attempts are shown. Versions in Java 15, 17 and 19 take advantage of records and Java's initial support for pattern matching. The other in Java 8.

comparison

Java 19 Attempt

Record patterns are now available and the Java version is nearly identical to the Scala version. Record patterns are limited to type comparison and extraction and so can't match on, for example, empty-list but that's about the only feature missing. Java is still more verbose (the need for var for example) but it's very impressive how close it now is. Java, of course, is still missing a built-in Pair syntax for list head/tail, etc.

Java 17 Attempt

Java records are now part of the language. My RecordBuilder library is still used for some builder sugar. Huge kudos to Gavin Ray for contributing the Java 17 version using Sealed Classes as well as Pattern Matching for Switch. This is getting very, very close to the Scala version now. Once deconstruction is added we'll have a nearly exact version.

Java 17's enhanced pattern matching for switch is missing reification and deconstruction. So, for now, a combination of the current pattern-matching-for switch with an extra pattern match for instanceof is used.

See the Java 15 attempt for what will be permanent issues with lack of a Pair and type aliasing.

Java 15 Attempt

Java 15’s Records are an interim feature towards full pattern matching and deconstruction. Java’s records are very close to Scala’s case classes (sans pattern matching/deconstruction which will come later). The only missing feature is a static constructor/builder method which makes allocating case classes a bit cleaner (no need for new). Fortunately, my RecordBuilder library can auto-generate these so I’ve used it here to match Scala.

The major thing missing in this Java 15 attempt is, of course, Scala’s case-match. Future versions of Java will add support for something similar but for now I’ve had to use Java 15’s new pattern matching for instanceof.

Java 15 is also missing a built-in Pair class. With records, however, this is very easy to create. Java also does not support type aliases. It’s unlikely Java will add support for this. Thus, the Scala example’s Environment and Name cannot be duplicated.

These caveats aside, the Java 15 attempt is not too bad. Once we get Java’s version of pattern matching it will be possible to write a near perfect duplication of this Scala example.

Java 8 Attempt

Java 8, of course, does not support anything like records or case classes. However, we can use generators such as Immutables to generate something close to a record. Having to use Java interfaces as a spec for the Immutables builder is not as satisfying and makes the code much more verbose. Also, the Immutables builder does not generate static constructors/builders so these have to be added manually.

Like in the Java 15 example, there is no built-in Pair class and in this Java 8 instance it has to be specified as an interface so that Immutables can generate the implementation.

Lastly, Java 8 does not have Java 15’s pattern matching for instanceof so extra work in the form of casts must be done in the parts of the code that match on operation types.

Links

Building/Running

  • Make sure Javas 8, 15, 17 and 19 are installed as well as jenv
  • Make sure a recent version of Maven is installed
  • From the root directory run ./run.sh