Skip to content

Cyclops X FINAL : Release version of Cyclops 10!

Compare
Choose a tag to compare
@johnmcclean johnmcclean released this 31 Aug 13:40
· 340 commits to master since this release
9835db0

Cyclops X FINAL (10.0.0-FINAL)

Cyclops X

Cyclops X (cyclops 10) unifies cyclops-react and the cyclops integration modules on the cyclops versioning scheme. The goal of this project is remove a whole class of runtime errors from application code by providing much stricter APIs that prevent exceptional states from arising. A secondary goal is to modularize cyclops into a series of smaller more focused projects so that functionality is easy to find and developers only take what they need.

What’s new Cyclops X

-> Enhancements over cyclops-react 2

  • Fast purely functional datastructures (Vector, Seq / List, LazySeq / LazyList, NonEmptyList, HashSet, TreeSet, TrieSet, HashMap, LinkedMap, MultiMap, TreeMap, BankersQueue, LazyString, Discrete Interval Encoded Tree, Zipper, Range, Tree, DifferenceList, HList, Dependent Map )
  • Structural Pattern Matching API (deconstruct algebraic product and sum types)
  • Improved type safety via the removal of unsafe APIs
    -- E.g. Unlike Optional, Option has no get method (which could throw a null pointer)
    -- New data structures do not support operations that would throw exceptions (you can't call head on an empty list for example)
  • Eager and Lazy alternatives for most datastructures (Option is eager, Maybe is lazy + reactive)
  • Improved naming of types (Function1-8 rather than Fn1-8, Either not Xor)
  • Group id is changed to com.oath.cyclops
  • Versioning between cyclops-react and cyclops is merged on cyclops versioning scheme (version 10 = Cyclops X)
  • Light weight dependencies : reactive-streams API & Agrona
  • JVM polyglot higher kinder types support via KindedJ

What’s new Cyclops X FINAL Release

  • API enhancement : remove limit / skip overloads (remains on ReactiveSeq for Stream compatibility)
  • Recursion and concurrent Evaluation enhancements to Eval
  • Performance enhancements : core operations improved for Vector, Seq, LazySeq
  • Make illegal states unrepresentable : LazySeq is 100% lazy
  • IO enhancements : synchronous IO and FutureStream based concurrent IO

API enhancement : remove limit / skip overloads

  • take / drop are used everywhere
  • only ReactiveSeq retains limit / skip as defined in the Stream API

Recursion and concurrent Evaluation enhancements to Eval

  • Eval zipping should focus on supporting interleaving the execution of Evals

The zip method on Eval can used to Evaluate multiple lazy code blocks concurrently, and only accepts another Eval, Trampoline or Supplier as a parameter.

public void interleave(){

        Eval<Integer> algorithm1 = loop(50000,Eval.now(5));
        Eval<Integer> algorithm2 = loop2(50000,Eval.now(5));

        //interleaved execution via Zip!
        Tuple2<Integer, Integer> result = algorithm1.zip(algorithm2,Tuple::tuple).get();

        System.out.println(result);
}

Eval<Integer> loop2(int times,Eval<Integer> sum){
        System.out.println("Loop-B " + times + " : " + sum);
        if(times==0)
            return sum;
        else
            return sum.flatMap(s->loop2(times-1,Eval.now(s+times)));
}

Eval<Integer> loop(int times,Eval<Integer> sum){
        System.out.println("Loop-A " + times + " : " + sum);
        if(times==0)
            return sum;
        else
            return sum.flatMap(s->loop(times-1,Eval.now(s+times)));
}
Producing output showing executing of interleaved lazy calls
Loop-B 15746 : Always[1126048874]
Loop-A 15745 : Always[1126064620]
Loop-B 15745 : Always[1126064620]
Loop-A 15744 : Always[1126080365]
Loop-B 15744 : Always[1126080365]
Loop-A 15743 : Always[1126096109]
Loop-B 15743 : Always[1126096109]
Loop-A 15742 : Always[1126111852]
Loop-B 15742 : Always[1126111852]
Loop-A 15741 : Always[1126127594]

Support Tail-recursion on methods that return a Supplier

Ensure a clean Eval can be created from a Supplier that supports tail-recursion on methods with JDK Friendly method signatures.

Supplier<Integer> loopSupplier(int times, int sum)
Then using Eval, this call shouldn't blow the stack
Supplier<Integer> algorithm1 = loopSupplier(50000,5);
System.out.println(algorithm1.get());
Provide a method to create an Eval from a Supplier
Supplier<Integer> loopSupplier(int times, int sum){
        if(times==0)
            return ()->sum;
        else
            return eval(()->sum).flatMap(s->Evala.eval(loopSupplier(times-1,s+times)));
}

Performance enhancements : core operations improved for Vector, Seq, LazySeq

Significant performance enhancements for append, get, setAt / update for core collections. E.g. Comparison with Vavr (post enhancements - Vavr was faster before) for Vector storing Strings

  • Append 10,000 Strings 50th percentile (ms/ops) :
  1. Vector (Vavr) : 0.222
  2. Vector (Cyclops) : 0.041
    https://github.com/aol/cyclops-react/blob/master/cyclops/src/jmh/java/cyclops/DataAppend.java

Make illegal states unrepresentable

** Make LazySeq totally lazy, solves numerous runtime errors and infinite loop issues
e.g. in Scala

Stream.continually(1)
	    .filter(i=>false)
            .take(0)
            .isEmpty //infinite loop that never finishes!

But Cyclops

LazySeq.generate(()->1)
	      .filter(I->false)
              .take(0)
              .isEmpty() //true! 

IO enhancements : synchronous IO and FutureStream based concurrent IO

  • Synchronous IO
    For purely synchronous IO this model of execution will give better performance
IO.sync(this::readData)
  .map(this::process)
  .map(this::save)
  .run()
  • FutureStream based IO for blocking concurrent operations
FutureStreamIO.of(Executors.newCachedThreadPool(), this::readUserDataFromCache, this::readUserDataFromDisk, this::readUserDataFromDB)
                .map(this::process)
                .map(this::save)
                .run()

Changelog

Check out the features delivered and bugs fixed -

github 10.0.0-FINAL issues & PRs

Dependency changes

Reactive Streams to 1.0.2

Modules

Get cyclops X

Gradle

Cyclops

compile 'com.oath.cyclops:cyclops:10.0.0-FINAL’

Cyclops AnyM

compile 'com.oath.cyclops:cyclops-anym:10.0.0-FINAL’

Cyclops Futurestream

compile 'com.oath.cyclops:cyclops-futurestream:10.0.0-FINAL’

Cyclops Pure

compile 'com.oath.cyclops:cyclops-pure:10.0.0-FINAL’

Cyclops Reactive Collections

compile 'com.oath.cyclops:cyclops-reactive-collections:10.0.0-FINAL’

Cyclops Reactor Integration

   compile 'com.oath.cyclops:cyclops-reactor-integration:10.0.0-FINAL'

Cyclops RxJava2 Integration

   compile 'com.oath.cyclops:cyclops-rx2-integration:10.0.0-FINAL'

Cyclops Jackson Integration

   compile 'com.oath.cyclops:cyclops-jackson-integration:10.0.0-FINAL'

Maven

Cyclops

<dependency>
    <groupId>com.oath.cyclops</groupId>
    <artifactId>cyclops</artifactId>
    <version>10.0.0-FINAL</version>
</dependency>

Cyclops AnyM

<dependency>
    <groupId>com.oath.cyclops</groupId>
    <artifactId>cyclops-anym</artifactId>
    <version>10.0.0-FINAL</version>
</dependency>

Cyclops Futurestream

<dependency>
    <groupId>com.oath.cyclops</groupId>
    <artifactId>cyclops-anym</artifactId>
    <version>10.0.0-FINAL</version>
</dependency>

Cyclops Pure

<dependency>
    <groupId>com.oath.cyclops</groupId>
    <artifactId>cyclops-pure</artifactId>
    <version>10.0.0-FINAL</version>
</dependency>

Cyclops Reactive Collections

<dependency>
    <groupId>com.oath.cyclops</groupId>
    <artifactId>cyclops-reactive-collections</artifactId>
    <version>10.0.0-FINAL</version>
</dependency>

Cyclops Reactor Integration

<dependency>
    <groupId>com.oath.cyclops</groupId>
    <artifactId>cyclops-reactor-integration</artifactId>
    <version>10.0.0-FINAL</version>
</dependency>

Cyclops RxJava2 Integration

<dependency>
    <groupId>com.oath.cyclops</groupId>
    <artifactId>cyclops-rx2-integration</artifactId>
    <version>10.0.0-FINAL</version>
</dependency>

Cyclops Jackson Integration

<dependency>
    <groupId>com.oath.cyclops</groupId>
    <artifactId>cyclops-jackson-integration</artifactId>
    <version>10.0.0-FINAL</version>
</dependency>

License

cyclops-react is licensed under the Apache 2.0 license.

http://www.apache.org/licenses/LICENSE-2.0#