Javaslang v0.9.1 Release Notes

Release Date: 2017-09-17 // over 6 years ago
  • Contributors

    Christian Bongiorno
    Daniel Dietrich
    Emmanuel Touzery
    Julien Debon
    Nazarii Bardiuk
    Pascal Schumacher
    Ruslan Sennov

    🔄 Changelog

    Concurrent operations

    • 🛠 We fixed a bug that prevented onFailure actions to be performed when a Future has been cancelled.
    • 👀 There are known problems with Promise that occur under certain circumstances (see details below). Please note that we did not fix this problem in 0.9.1. We currently work on it in #2093. 0️⃣ The main thread may be blocked forever if we use an operation that blocks on a Future returned by a Promise. We observed this behavior when we used a ForkJoinPool instead of the default CachedThreadPool. Example: // we choose a work-stealing thread pool ExecutorService executor = java.util.concurrent.ForkJoinPool.commonPool(); Future<Object> someFuture = Future.of(executor, () -> longRunningTask());

    // the internal Future of a Promise might deadlock the system if we block on that Future Promise<Object> promise = Promise.make(executor); someFuture.onComplete(promise::complete);

    // the bug only shows up when calling a blocking operation, like get() or isEmpty() Object result = promise.future().get();

    Numeric operations

    • ✂ Removed the Traversable.min(), max() overloads TreeSet.min() and TreeSet.max()
    • Made Traversable.average(), sum() and product() more accurate. TreeSet min()/max() TreeSet implements SortedSet, which represents distinct elements that are ordered using a specific Comparator. 0️⃣ By default, Traversable.min() and max() calculate the minimum resp. maximum element in linear time O(n) using the natural element order. However, we used the TreeSet collection characteristic to calculate the min() / max() in constant time O(1). This was wrong for two reasons: The Traversable API spec states that min() and max() are calculated using the natural element order. This has to be the case because of the Liskov substitution principle, see examples below. The minimum of any non-empty collection containing double values is Double.NaN if one or more elements are NaN. But the natural Comparator of Double is defined in the way that NaN >= d for every double d. Example: // = TreeSet(3, 2, 1) Set<Integer> ints = TreeSet.of(Comparator.reverseOrder(), 1, 2, 3);

    // = 3 (before), = 1 (after) ints.min();

    // = 1 (before), = 3 (after) ints.max();

    // = List(1.0, NaN, 3.0) List<Integer> doubles = List.of(1.0, Double.NaN, 3.0);

    // = 1.0 (before), = NaN (after) doubles.min();

    // = NaN (both ok, before and after this change) doubles.max(); Traversable average(), sum() and product() sum() and product() operate on elements of type Number. Now we return a Number according to the input argument or fallback to double. 🛠 sum() and average() now internally use an improved summation compensation algorithm that fixes problems that occur in standard Java. Example: // = OptionalDouble(0.0) (wrong) j.u.s.DoubleStream.of(1.0, 10e100, 2.0, -10e100).average()

    // = Some(0.75) (correct) List.of(1.0, 10e100, 2.0, -10e100).average()

    Missing methods

    We added

    • Either.sequence(Iterable<? extends Either<? extends L, ? extends R>>)
    • Either.sequenceRight(Iterable<? extends Either<? extends L, ? extends R>>) Examples: // = Right(List(all, right)) of type Either<Seq<Integer>, Seq<String>> Either.sequence(List.of(Either.right("all"), Either.right("right")));

    // = Left(List(1, 2)) of type Either<Seq<Integer>, Seq<String>> Either.sequence(List.of(Either.left(1), Either.left(2), Either.right("ok")));

    // = Right(List(all, right)) of type Either<Integer, Seq<String>> Either.sequenceRight(List.of(Either.right("all"), Either.right("right")));

    // = Left(1) of type Either<Integer, Seq<String>> Either.sequenceRight(List.of(Either.left(1), Either.left(2), Either.right("ok")));

    Type narrowing

    We changed the generic bounds of these method arguments:

    • Function0<R>.narrow(Function0<? extends R>) (before: narrow(Supplier<? extends R>))
    • Function1<T1, R> Function1.narrow(Function1<? super T1, ? extends R>) (before: narrow(Function<? super T1, ? extends R>))
    • Function2<T1, T2, R> Function2.narrow(Function2<? super T1, ? super T2, ? extends R>) (before: narrow(BiFunction<? super T1, ? super T2, ? extends R>)) Background: Java is not able to do the following type assignment: M<? extends T> m = ...; M<T> narrowed = m; // does not work but it is correct for immutable objects. Therefore almost all Vavr types have narrow methods. M<? extends T> m = ...; M<T> narrowed = M.narrow(m); // works as expected ### 🛠 GWT compatibility fixes

    The following methods were annotated with @GwtIncompatible:

    • Predicates#instanceOf(Class)
    • asJava(), asJava(Consumer), asJavaMutable(), asJavaMutable(Consumer) of io.vavr.collection.Seq and all its subtypes,
      namely IndexedSeq, LinearSeq, Array, CharSeq, List, Queue, Stream and Vector

    📚 Documentation

    We added more examples and improved the readability of the Javadoc:

    javadoc

    💅 Thanks to Stuart Marks, he was so kind to initiate an issue in order to improve the default Javadoc style.

    You find the Vavr 0.9.1 API specification here.

    🛠 More fixes...

    • 🚚 We removed internal memoization of sortBy() in order to fix an issue with lazy collections that have infinite size
    • ⚡️ We optimized collection conversion
    • 🏗 We fixed the generics of Multimap builders
    • We improved Traversable.reduceLeft
    • We improved Iterator.dropWhile and slideBy

    Please find the complete list of changes here.