Fast Forward >> Vavr 1.0
It has been a while since our last blog post and we have much to tell.
Three months ago we released Vavr 0.9, the first release after our rebranding. We urgently needed that release for several reasons, for example because spring-data now supports our library and it needed a stable Vavr release.
To that time we were already behind our schedule towards Javaslang 2.1 which included many improvements, several new collections and a blazing fast new Vector implementation.
We had already planned several changes for Javaslang 3.0 that affected backward compatibility. When we heard that we needed to change our name it first was a shocking moment. But in fact it helped us shipping the next release.
We skipped 2.1 and changed the version to 0.9. The negative version jump should indicate, that we wanted to start fresh and 1.0 will follow in not too distant future.
We intentionally pulled into 0.9 as many backward compatibility affecting changes as possible because we wanted to move forward. The rebranding affected also our package names, which made it impossible to use Vavr as drop-in replacement for Javaslang.
While the first patch release Vavr 0.9.1 is in the make and will be released soon, we are already planning the future of Vavr.
What to expect from Vavr
We collected the user feedback over the last months and distilled the essence. We think these are the topics our users are concerned about (without weights):
- the ability to choose features, also related to integration of new features and the footprint
- interoperability with Java, especially the collections and name conflicts
- backward compatibility, also related to seamless version upgrades
- adoption of future Java features, e.g. modularization and value types
- better documentation
Modularization
From the user perspective, slicing Vavr's main library into several modules helps to select features. We gain the freedom to choose and have better control over the footprint.
Main modules also help the contributors in terms of maintainability. Dependencies between Vavr features get visible. Minimizing these dependencies reduces the overall complexity. Build times could be optimized, test iterations might get faster and so on. Also this goes hand-in-hand with the definition of Java 9 modules (which is already in the make).
Slicing Vavr into smaller parts will break backward compatibility. At a first sight, only the static sequence() factory methods and the Value conversion methods are affected. Java 9 modules require also the adjustment of split package names. We will be able to keep the functionality but the API will change.
To give you a better impression of how Vavr main modules could look like, I want to show you a draft. This is the basis for a discussion.
At its core, Vavr offers functions, tuples and an interface Value that is the common type of most Vavr classes. Beside these, the core will contain Lazy (laziliy evaluated values) and two popular and widely used controls, Option (null-safety) and Try (error-handling).
Side note: With Java support for primitive generics, the interfaces CheckedConsumer, CheckedPredicate and CheckedRunnable will become obsolete. They will be replaced by the existing CheckedFunction1<T, void>, CheckedFunction1<T, boolean> and CheckedFunction0<void>.
More controls can be loaded by including vavr-controlx, e.g. Either and Validation. We decided to add the suffix 'x' to extension modules/packages because Java 9 modules are not allowed to contain duplicate package names.
Our ever-growing collection library is split into two modules, vavr-collection and vavr-collectionx. The former will contain the most popular and most widely used collections, also known from Java and Scala. The latter will contain additional collections that might come handy, depending on the use-case.
The vavr-concurrent module will contain our functional alternative to CompletableFuture. I think we will fuse Future and Promise by using a higher-order function to resolve/reject an async computation. Much like how the EcmaScript Promise works. Please see issue #1529.
We can't change the Java language by ourselves. All features that try to do so, e.g. pattern matching and for comprehensions, will be moved to a separate module vavr-api. Because different Java 9 modules can't export the same package, the package name needs to be changed.
Please note that Java will come up with native pattern matching. Therefore the use of vavr-api is discouraged but it will still be maintained.
All main modules mentioned above (excluding vavr-api and the co-module vavr-match) will be available as one big bundle, called vavr-all-in-one.
Beside the main modules we already talked about, namely
- vavr-core
- vavr-collection
- vavr-concurrent
- vavr-collectionx
- vavr-controlx
- vavr-api
- vavr-match
there are several existing and upcoming auxiliary modules.
3rd party library support
- vavr-jackson
- vavr-gwt
- vavr-hibernate*)
- vavr-gson*)
Language support
- vavr-kotlin*)
Add-ons
- vavr-test
- vavr-render
- vavr-parser*)
- vavr-generator**)
Interoperability
One of Java's greatest strengths is its big eco-system. Interoperability is a key to success for a Java library.
Our persistent collections are named like the old-school Java collections because we intended to ship a full-featured functional replacement. The reality looks different. Developers use Java collections and Vavr collections side-by-side.
Because of the overlapping collection names our users need to fully qualify class names. I want to fix this issue by renaming our collections. Please give input, we need a prefix!
Frequently someone asks why our persistent collections do not implement the standard Java collection interfaces. This is still a no-go. Our users would suffer because it would mix the functional paradigm (changes return new versions) and the imperative paradigm (changes perform side-effects or throw).
We already have an answer to this kind of interoperability. We provide standard Java collection views. Instead of copying the collection elements, we are able to create a view in constant time and memory. For the case that a native Java collection instance is needed, we provide several conversion methods.
Renaming our collections should solve the last interopability issue.
Backward compatibility
To be honest, thinking that semantic versioning solves the backward compatibility issue is foolish. Even the new Java 9 module system has no answer to it. Every little change, even an internal patch, may lead to backward compatibility issues. Currently the only reliable solution to use different versions in parallel is to repackage dependencies during the build phase.
Java 9, 10 and beyond
Beside the controversely discussed Java Platform Module System there are many exciting new Java features in the pipeline, namely pattern matching, value types and primitive generics.
These changes are important for Vavr. We will be able to improve the cpu and memory consumption of our types and remove workarounds for missing language features.
Value types are in line with functional programming, they are immutable. In contrast to nominal types, value types do not own an object reference. This has several implications, most notably that equality is defined (recursively) by content. The values will be flattened internally, this will save memory and will speed up read-access.
Many Vavr types are algebraic data types, like our tuples, controls and (some) collections. If we are able to make value types out of tuples, they will not be wrapped anymore. Instead Java will flatten the tuple components and remove previous object headers. That is really nice!
Currently it is not planned by Java language architects to support recursive value type definitions. This means it looks like we will not be able to convert our sum-types, e.g. Option and Try, to value types. We will see.
There is one more thing to tell about value types, I think we will get sealed interfaces. They ensure that only a fixed set of (value) classes implement an interface. Given that, the compiler is able to check if a pattern matching expression is exhaustive, i.e. safe.
We are really looking forward to native pattern matching, it will make our Match API obsolete.
The last upcoming feature we mentioned, support for primitive generics, will reduce the amount of functional interfaces and simplify our collections, like CharSeq.
Please note that it might take years before Java will ship these features. However, we need to prepare our library in order to evolve side-by-side to Java.
Documentation
I see great potential regarding our documentation. It will receive some love by time. I think 1.0 should not be released before the documentation is finished.
Also a new web-page would be awesome, we will see ;)
I'm really excited, there are many intersting activities ongoing and developing one of the most popular functional libraries for Java is still fun. We learn from the past and move the project forward. In order to reduce the risk I'm now sharing the ownership of the Github organization with my dear fellow Ruslan. Thank you, Ruslan!
Happy coding!
Daniel