Skip to content

Releases: aol/cyclops

Cyclops X - Milestone 1

03 Nov 20:46
Compare
Choose a tag to compare

Milestone one of 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

Changelog

Check out the features delivered and bugs fixed -

github 10.0.0-M1 issues & PRs

Dependency changes

Cyclops no longer depends on pCollections or jOOλ

Get cyclops X

Gradle

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

Maven

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

Documentation

Articles

Old simple-react landing page

License

cyclops-react is licensed under the Apache 2.0 license.

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

v2.1.1 of cyclops-react : Bug fixes and minor enhancements

04 Oct 10:21
Compare
Choose a tag to compare

2.1.1 of cyclops-react

What’s new cyclops-react v2.1.1

Various bug fixes.

  • Fix bug in ListX.with method
  • Eval.now filter issue
  • Unlawful Groups removed

Enhancements

  • JDK 9 Iterate methods for extended collections
  • Kleisli for comprehensions
  • Static tailRec methods on monad types

Changelog

Check out the features delivered and bugs fixed -

github 2.1.1 issues & PRs

Dependency upgrades

None this time

Get cyclops-react

Gradle

compile 'com.aol.simplereact:cyclops-react:2.1.1’

Maven

<dependency>
    <groupId>com.aol.simplereact</groupId>
    <artifactId>cyclops-react</artifactId>
    <version>2.1.1</version>
</dependency>

Documentation

Articles

Old simple-react landing page

License

cyclops-react is licensed under the Apache 2.0 license.

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

v2.1.0 of cyclops-react : Enhanced typeclasses, easier reactive-streams

11 Aug 13:44
Compare
Choose a tag to compare

2.1.0 of cyclops-react

What’s new cyclops-react v2.1.0

MonadRec typeclass

http://functorial.com/stack-safety-for-free/index.pdf Stack Safety for Free

MonadRec<maybe> mr = Maybe.Instances.monadRec();
Maybe<Integer> l = mr.tailRec(0, i -> i < 100_000 ? Maybe.just(Xor.secondary(i + 1)) : Maybe.just(Xor.primary(i + 1)))
                     .convert(Maybe::narrowK);
//Just[100_001];

Also available on Active

Active<list,Integer> list = ListX.of(1,2,3).allTypeclasses();
list.concreteTailRec(ListX.kindKleisli())
        .tailRec(1,i-> 1<100_000 ? ListX.of(Xor.secondary(i+1)) : ListX.of(Xor.primary(i)));

//List[100_001]

Enumeration data type and enum Streaming support

 ReactiveSeq.enums(Days.class)
                      .printOut();

Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday

Enumeration.enums(Days.values())
                     .stream(Monday)
                     .join(" ")
//"Monday Tuesday Wednesday Thursday Friday Saturday Sunday"
Enumeration.enums(ListX.of(A,B,C,D,E,F,G,H,I,J))
                     .streamThenTo(A,C,G)
                     .join(" ");

"A C E G"

An effect type for composing side-effects

E.g. asycnhronously push data into an Observable style stream, cycling 30 times

Subscription sub = Spouts.asyncBufferBlock(10, s -> {
            if (i == 0) {
                Effect e = () -> {
                    s.onNext("hello " + i++);
                };
                e.cycle(30).runAsync();
            }
        }
    ).forEach(2, in->count++);

Buffering factory methods for reactive-streams and other async Stream types

reactiveBuffer creates a buffering reactive-streams Stream. User code can ignore incoming request information, this is managed by the buffering Stream. Pushed events are buffered before being sent downstream when requested. Users can set the overflow policy between block and drop.

Subscription sub = Spouts.reactiveBuffer(16, s -> {

    s.onSubscribe(new Subscription() {
        @Override
        public void request(long n) {
            if(i==0) {

                Effect e = () -> {


                    s.onNext("hello " + i++);
                };
                e.cycle(30).runAsync();
            }
        }

        @Override
        public void cancel() {

        }
    });

}).forEach(2, in->count++);


//count will be 2, buffer will be 16
Thread.sleep(500);

sub.request(30);

assertThat(i,equalTo(30));
assertThat(count,equalTo(18));

Changelog

Check out the features delivered and bugs fixed -

github 2.1.0 issues & PRs

Dependency upgrades

None this time

Get cyclops-react

Gradle

compile 'com.aol.simplereact:cyclops-react:2.1.0’

Maven

<dependency>
    <groupId>com.aol.simplereact</groupId>
    <artifactId>cyclops-react</artifactId>
    <version>2.1.0</version>
</dependency>

Documentation

Articles

Old simple-react landing page

License

cyclops-react is licensed under the Apache 2.0 license.

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

v2.0.0-FINAL of cyclops-react

04 Jul 15:57
Compare
Choose a tag to compare

2.0.0-FINAL of cyclops-react

What’s new cyclops-react v2 - FINAL

Reactive Try

Try is now a Reactive data type, Try can operate eagerly (e.g. via Try.success, Try.failure,Try.withCatch, Try.runWithCatch), lazily (Try.fromIterable, Try.fromXor when an Either is used) or reactively (Try.fromPublisher or via toTry() on another reactive type).

A Reactive Try

ReactiveSeq<Integer> reactiveStream; //async populate a Stream with [1,2,3]

Try<Integer,Throwable> attempt = Try.fromPublisher(reactiveStream, RuntimeException.class);
Try<Integer,Throwable> doubled = attempt.map(i->i*2);

//when the data arrives doubled will be (first value from the Stream doubled)
//Try[2]

An Eager try

Try<Integer,Throwable> attempt = Try.success(1);
Try<Integer,Throwable> doubled = attempt.map(i->i*2);

//doubled will immediately be 
//Try[2]

A lazy try

ReactiveSeq<Integer> reactiveStream = ReactiveSeq.of(1,2,3);

Try<Integer,Throwable> attempt = Try.fromIterable(stream);
Try<Integer,Throwable> doubled = attempt.map(i->i*2);

//doubled when accessed first will become
//Try[2]

Concurrency via Trampoline zip (& also in Free & Unrestricted)

Interleave execution of two looping algorithms

Trampoline<Integer> looping = loop(500000,5);
Trampoline<Integer> looping2 = loop2(500000,5);
System.out.println(looping.zip(looping2).get());

Trampoline<Integer> loop2(int times,int sum){

    System.out.println("Loop-B " + times + " : " + sum);
       if(times==0)
           return Trampoline.done(sum);
       else
           return Trampoline.more(()->loop2(times-1,sum+times));
   }

Trampoline<Integer> loop(int times,int sum){
       System.out.println("Loop-A " + times + " : " + sum);
	if(times==0)
		return Trampoline.done(sum);
	else
		return Trampoline.more(()->loop(times-1,sum+times));
}

Prints

…
Loop-A 54 : 446196936
Loop-B 54 : 446196936
Loop-A 53 : 446196990
Loop-B 53 : 446196990
Loop-A 52 : 446197043
Loop-B 52 : 446197043
…

Concurrency via recursive data types

To execute two recursive algorithms simulatationously, convert to a Trampoline and zip!

public void odd(){
    even(Maybe.just(200000)).toTrampoline()
                          .zip(odd1(Maybe.just(200000)).toTrampoline()).get();
}
public Maybe<String> odd(Maybe<Integer> n )  {
    System.out.println("A");
    return n.flatMap(x->even(Maybe.just(x-1)));
}
public Maybe<String> even(Maybe<Integer> n )  {
    return n.flatMap(x->{
        return x<=0 ? Maybe.just("done") : odd(Maybe.just(x-1));
    });
}
public Maybe<String> odd1(Maybe<Integer> n )  {
    System.out.println("B");
    return n.flatMap(x->even1(Maybe.just(x-1)));
}
public Maybe<String> even1(Maybe<Integer> n )  {
   
    return n.flatMap(x->{
        return x<=0 ? Maybe.just("done") : odd1(Maybe.just(x-1));
    });
}

Prints out

A
B
A
B
A
B
A

XorM and Coproduct

A Sum type for monads of the same type.
XorM / Coproduct are active type biased (rather than right biased).

e.g.

XorM<stream,optional,Integer> nums = XorM.stream(1,2,3)
                                                    .swap();
int result = nums.map(i->i*2)
                .foldLeft(Monoids.intSum);
//12
}

Active and Nested data types

Active wraps a HKT encoding and any associated typeclasses to provide a fluent java friendly interface. Nested does the same for nested HKT encodings (e.g. an Optional inside a List)

Active<list,Integer> active = Active.of(ListX.of(1,2,3),ListX.Instances.definitions());
Active<list,Integer> doubled = active.map(i->i*2);
Active<list,Integer> doubledPlusOne = doubled.flatMap(i->ListX.of(i+1));
import cyclops.monads.Witness.list;
import cyclops.monads.Witness.optional;

Nested<list,optional,Integer> listOfOptionalInt = Nested.of(ListX.of(Optionals.OptionalKind.of(2)),ListX.Instances.definitions(),Optionals.Instances.definitions());
//Nested[List[Optional[2]]]

 Nested<list,optional,Integer> listOfOptionalInt;  //Nested[List[Optional[2]]]
Nested<list,optional,Integer> doubled = listOfOptionalInt.map(i->i*2);
//Nested[List[Optional[4]]]

Unfoldable type class

The unfoldable type class allows types to be recursively expanded (e.g. to generate a List from a function)

  Unfoldable<list> unfoldable = ListX.Instances.unfoldable();
  ListX<Integer> unfolded = unfoldable.unfold(1,i->i<=6 ? Optional.of(Tuple.tuple(i,i+1)) : Optional.empty());
 //(1,2,3,4,5)

Yoneda, Coyoneda and Cofree data types

Coyoneda allows you use custom data types as if they were Functors with Free (without having to define a custom Functor), simplifying some of the machinery required to use the Free Monad.

Functor<Higher<Higher<coyoneda, Command>, Void>> commandFunctor  = Coyoneda.functor();
val lifted = Free.liftF(new MyCommand<>(a, null), commandFunctor);

Changelog

Check out the features delivered and bugs fixed -

github 2.0.0-FINAL issues & PRs
github 2.0.0-RC8 issues & PRs
github 2.0.0-RC1 issues & PRs

Dependency upgrades

None this time

Get cyclops-react

Gradle

compile 'com.aol.simplereact:cyclops-react:2.0.0-FINAL’

Maven

<dependency>
    <groupId>com.aol.simplereact</groupId>
    <artifactId>cyclops-react</artifactId>
    <version>2.0.0-FINAL</version>
</dependency>

Documentation

Articles

Old simple-react landing page

License

cyclops-react is licensed under the Apache 2.0 license.

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

v2.0.0-MI7 of cyclops-react

06 Jun 15:19
Compare
Choose a tag to compare

2.0.0-MI7 of cyclops-react

What’s new cyclops-react v2 Milestone 7?

  • Kotlin style sequence generators
  • Bug fixes

Some Examples

#e.g. with suspend and yield operators - note providing a BooleanSupplier indicates the suspended block should be executed until false (in this case infinitely).

int i = 100;
ReactiveSeq.generate(suspend(infinitely(),s->s.yield(i++)))
           .take(6)
           .printOut();

/**
100
101§
102
103
104
105
106
**/

Execute the suspended block just once (itself meaningless unless we can also sequence actions)

int i = 100;
ReactiveSeq.generate(suspend(s->s.yield(i++)))
           .take(6)
           .printOut();

/**
100
**/

Yield a sequence of values

ReactiveSeq.generate(suspend(times(10),s-> {
            System.out.println("Top level - should repeat after sequence completes!");
            return s.yield(1,
                           () -> s.yield(2),
                           () -> s.yield(3),
                           () -> s.yield(4));
                       }))
           .take(6)
           .printOut();    

Support method references

Generator<Integer> generator = suspendRef(times(10),this::next);
generator.stream()
         .forEach(System.out::println);

List<Integer> list = generator.to()
                              .linkedListX(LAZY)
                              .type(VavrTypes.list())
                              .map(this::process)          
                              .to(VavrConverters::LIST);
public Integer next(){
        return i++;
}
int i = 100;

Method references directly during yielding

ReactiveSeq.generate(suspend(times(10),s-> {
                    System.out.println("Top level - should repeat after sequence completes!");
                    return s.yieldRef(1,
                                      Generator::next,
                                      Generator::next,
                                      Generator::next,
                                      Generator::next);
                }
        )).take(6)
          .printOut();
public Integer next(){
        return i++;
}

More managable / complex mutable state via Inner Classes (if really needed)

ReactiveSeq.<Integer>generate(suspend(times(10),new ContFunction<Integer>() {
                    int runningTotal =0;

                   @Override
                   public Generator<Integer> apply(Suspended<Integer> s) {
                       System.out.println("Top level - should repeat after sequence completes!");
                       return s.yield(1,
                               () -> {
                                    runningTotal = runningTotal +5;
                                    return s.yield(runningTotal+2);
                               },
                               () -> s.yield(runningTotal+3),
                               () -> s.yield(runningTotal+6));

                   }
               }

        )).take(6)
          .printOut();

Control looping based on current value and support safe (s.maybe()) and unsafe (s.current()) to the current value.

ReactiveSeq.generate(suspend((Integer i)->i==4,s-> {
                    System.out.println("Top level - repeat infinetely after sequence (because we return 4!)");
                    return s.yield(1,
                            () -> s.yield(s.maybe()
                                            .map(o->o+5)
                                            .orElse(10)),
                            () -> s.yield(s.current()),
                            () -> s.yield(4));
                }
        )).take(120)
          .printOut();

Supporting nested generators would allow very fine control over generating data sources..

  ReactiveSeq.generate(suspend((Integer i)->i!=4, s-> {
              
                    
                    Generator<Integer> gen1 = suspend(times(5),
                            s2->s2.yield(i++));
                    Generator<Integer> gen2 = suspend(times(2),
                                s2->s2.yield(k--));
                    
                    return s.yieldAll(gen1.stream(),
                            gen2.stream());
                }
        )).take(12)
                .printOut();

Changelog

Check out the features delivered and bugs fixed -

github 2.0.0-MI7 issues & PRs

Dependency upgrades

None this time

Get cyclops-react

Gradle

compile 'com.aol.simplereact:cyclops-react:2.0.0-MI7’

Maven

<dependency>
    <groupId>com.aol.simplereact</groupId>
    <artifactId>cyclops-react</artifactId>
    <version>2.0.0-MI7</version>
</dependency>

Documentation

Articles

Old simple-react landing page

License

cyclops-react is licensed under the Apache 2.0 license.

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

v2.0.0-MI6 of cyclops-react

26 May 11:50
Compare
Choose a tag to compare

2.0.0-MI6 of cyclops-react

What’s new cyclops-react v2 Milestone 6?

  • Xtended collections easy unwrapping and conversions
  • Better 3rd party support for Xtended Collections
  • API enhancements
  • Package reorganization to make it easier to find features
  • Unrestricted - a simplified version of Free
  • AnyM retains reactive nature for reactive monads
  • Easy conversion and extraction from Monad Transformers
  • Other enhancements and bug fixes

Some Examples

Unwrapping Xtended types

LinkedList<Integer> list1 = ListX.of(1,2,3)
                                 .toConverters::LinkedList);

3rd party support for Xtended Collections

VectorX<Integer> list1 = VectorX.of(1,2,3)
			        .type(VavrTypes.vector());

Changelog

Check out the features delivered and bugs fixed -

github 2.0.0-MI6 issues & PRs

Dependency upgrades

None this time

Get cyclops-react

Gradle

compile 'com.aol.simplereact:cyclops-react:2.0.0-MI6’

Maven

<dependency>
    <groupId>com.aol.simplereact</groupId>
    <artifactId>cyclops-react</artifactId>
    <version>2.0.0-MI6</version>
</dependency>

Documentation

Articles

Old simple-react landing page

License

cyclops-react is licensed under the Apache 2.0 license.

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

v2.0.0-MI5 of cyclops-react

26 Apr 14:11
Compare
Choose a tag to compare

2.0.0-MI5 of cyclops-react

What’s new cyclops-react v2 Milestone 5?

  • Asynchronous caching for Functions
  • Performance improvement for combinations
  • More efficient use of Queues in FutureStreams
  • Other enhancements and bug fixes

Changelog

Check out the features delivered and bugs fixed -

github 2.0.0-MI5 issues & PRs

Dependency upgrades

None this time

Get cyclops-react

Gradle

compile 'com.aol.simplereact:cyclops-react:2.0.0-MI5’

Maven

<dependency>
    <groupId>com.aol.simplereact</groupId>
    <artifactId>cyclops-react</artifactId>
    <version>2.0.0-MI5</version>
</dependency>

Documentation

Articles

Old simple-react landing page

License

cyclops-react is licensed under the Apache 2.0 license.

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

v2.0.0-MI4 of cyclops-react - Kleisli and new Monad types

22 Feb 15:35
Compare
Choose a tag to compare

2.0.0-MI4 of cyclops-react

What’s new cyclops-react v2 Milestone 4?

New Monads and types for working with Monads

  • Kleisli
  • Cokleisli
  • Writer
  • State
  • ReaderWriterState

Kleisli example

Define a function that creates a Stream

import cyclops.monads.Witness.reactiveSeq;



Kleisli<reactiveSeq, Integer, Integer> k1 = t -> ReactiveSeq.iterate(0,i->i<t, i->i+1)
                                                            .anyM();

k1.flatMap(i-> t-> ReactiveSeq.of(t+i)
                              .anyM())
  .apply(10)
  .forEach(System.out::println);

10
11
12
13
14
15
16
17
18
19

Changelog

Check out the features delivered and bugs fixed -

github 2.0.0-MI4 issues & PRs

Dependency upgrades

None this time

Get cyclops-react

Gradle

compile 'com.aol.simplereact:cyclops-react:2.0.0-MI4’

Maven

<dependency>
    <groupId>com.aol.simplereact</groupId>
    <artifactId>cyclops-react</artifactId>
    <version>2.0.0-MI4</version>
</dependency>

Documentation

Articles

Old simple-react landing page

License

cyclops-react is licensed under the Apache 2.0 license.

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

v2.0.0-MI3 of cyclops-react : More reactive types and Streams

06 Feb 17:23
Compare
Choose a tag to compare

2.0.0-MI3 of cyclops-react

What’s new cyclops-react v2 Milestone 3?

MI3 of v2 introduces a new push based / event driven ReactiveSeq implementation. Push based Streams can be created via the Spouts Factory class and can operate either in non-blocking Backpressure aware (reactive-streams) or back pressure free mode.

In addition core cyclops-react functional types including :- Maybe, Either, Either3, Either4, Either5, Eval, ListX, SetX, SortedSetX, QueueX, DequeX, PStackX, PVectorX, PSetX, POrderedSetX, PQueueX, PBagX can all operate as non-blocking reactive types (alongside Future and FutureStream).

A host of new operators have been added including : fanOut, parallelFanOut, Java 9 style iterate, deferred, ofNullable, multicast, broadcast, publishTo, changes, ambWith, findOne, firstOrError and more.

New types introduced include MaybeT, OptionalT, EvalT, CompletableFutureT, StreamT type safe, higher kinded monad transformers

  • ReactiveSeq supports non-blocking push based Streams
   ReactiveSeq<Integer> input = Spouts.async(subscriber->{
           
                                               listener.onEvent(subscriber::onNext);
                                                          
                                              listener.onError(susbscriber::onError);
                                                                                                        
                                              closeListener.onEvent(subscriber::onClose);
 
                                                     });

input.map(this::process)
     .forEach(this::handleResult,this::handleError,this::finish);
  • And non-blocking backpressure via reactive-streams for asynchronous and synchronous Streams
ReactiveSeq<Integer> input = Spouts.publishOn(ReactiveSeq.of(1,2,3),
                                              Executors.newFixedThreadPool(1));

Subscription sub = input.map(this::process)
                        .subscribe(this::handleResult,this::handleError,this::finish);

sub.request(2);
  • An array of non-blocking Reactive Types

Collections

ReactiveSeq<Integer> input = Spouts.publishOn(ReactiveSeq.of(1,2,3),
                                              Executors.newFixedThreadPool(1));

ListX<Integer> res = input.map(this::process)
                      .toListX();

this.continueProcessing();
currentThreadIsNotBlocked();

Integer thisBlocksThough = res.get(5);

//ListX, SetX, DequeX, QueueX, QueueX and persistent analogs populated asynchronously, without blocking the current Thread


Maybe

ReactiveSeq<Integer> input = Spouts.publishOn(ReactiveSeq.of(1,2,3),
                                              Executors.newFixedThreadPool(1));

Maybe<Integer> res = input.map(this::process)
                      .findOne();

//Maybe populated asynchronously and without blocking the current thread.

Either

ReactiveSeq<Integer> input = Spouts.publishOn(ReactiveSeq.of(1,2,3),
                                              Executors.newFixedThreadPool(1));

Either<Throwable,Integer> = input.map(this::process)
                                 .findFirstOrError();

//Either populated asynchronously and without blocking the current thread.

And more!

Eval, Either3-5, ListX,SetX,QueueX,DequeX,SortedSetX,PStackX,PVectorX,PQueueX,PSetX,POrderedSetX,PBagX

Completable Types

2.0.0-MI3 introduces CompletableMaybe, CompletableEval and CompletableEither(3-5).
Completable types allow a dataflow to be defined and completed asynchronously.

//create a CompletableEither
CompletableEither<Integer,Integer> completable = Either.either();

//define the data flow
Either<Throwable,Integer> mapped = completable.map(i->i*2)
                                  
                                              .flatMap(i->Eval.later(()->i+1));


//potentially asynchronously / on another thread push a value into the Eithercompletable.complete(5);


//execute the dataflow and printout

mapped.printOut();
assertThat(mapped.get(),equalTo(11));

//or connect to another reactive type asynchronously
Spouts.from(mapped)
      .forEach(this::continueProcessing,this::handleErrors);

Changelog

Check out the features delivered and bugs fixed -

github 2.0.0-MI3 issues & PRs

Dependency upgrades

None this time

Get cyclops-react

Gradle

compile 'com.aol.simplereact:cyclops-react:2.0.0-MI3’

Maven

<dependency>
    <groupId>com.aol.simplereact</groupId>
    <artifactId>cyclops-react</artifactId>
    <version>2.0.0-MI3</version>
</dependency>

Documentation

Articles

Old simple-react landing page

License

cyclops-react is licensed under the Apache 2.0 license.

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

v2.0.0-MI1 of cyclops-react

07 Jan 23:43
Compare
Choose a tag to compare

2.0.0-MI1 of cyclops-react

What’s new cyclops-react v2?

  • ReactiveSeq is replayable
ReactiveSeq<Integer> range = ReactiveSeq.range(0,1);
range.forEach(System.out::println);
range.map(this::process).forEach(System.out::println);
  • Collections are lazy
ListX<Data> load = ListX.of(1,2,3)
                        .map(i->i*2)
                        .filter(i->i<3)
                        .map(this::lookup);

Unlike most other functional style collection implementations load is a lazy refernce and the dataflow is only executed (once) on initial access. This gives much better performance for chained dataflows as the collection is traversed only once.

  • Streaming engine behind ReactiveSeq rewritten from scratch to be both replayable and ultra-efficient
  • Parralel sections within a sequential Stream
ReactiveSeq.generate(this::nextValue)
           .map(this::process)
           .parallel(new ForkJoinPool(10), 
                     par->par.map(this::cpuIntensiveOp)
                             .filter(this::accept))
           .forEach(this::store);

The parallel section is executed in parallel, the rest executed sequentially

  • Free Monad implementation for functional interpreters
  • Type safe, higher kinded AnyM implementation using Witness types
AnyM<optional,Integer> opt = by2(AnyM.ofNullable(10));
AnyM<stream,Integer> stream = by2(AnyM.fromArray(10,20,30));

Stream<Integer> rawStream = stream.to(Witness::stream);
Optional<Integer> rawOptional = opt.to(Witness::optional);

public <W extends WitnessType<W>> AnyM<W,Integer> by2(AnyM<W,Integer> toMultiply){

   return toMultiply.map(i->i*2);

}
  • Lazy tail recursive Either implementations (Either through Either5)
  • Higher kinded types for core cyclops-react types
  • Higher kinded type classes fro core cyclops-react types
  • Interface rationalization - more focused types, better naming

e.g. LazyFutureStream becomes FutureStream

Still to come (work in progress)

  • Pure push sequential ReactiveSeq implementation
ReactiveSubscriber<Integer> pushable = ReactiveSeq.pushable();
ReactiveSeq<Integer> stream = pushable.stream();

stream.map(i->i*2)
      .forEach(System.out::println);

pushable.onNext(10);

//20

See cyclops.StreamSource to push data into pull based sequential Streams.

Changelog

Check out the features delivered and bugs fixed -

github 2.0.0-MI1 issues & PRs

Dependency upgrades

Agrona to 0.9.1
Jooλ to 0.9.12

Get cyclops-react

Gradle

compile 'com.aol.simplereact:cyclops-react:2.0.0-MI1’

Maven

<dependency>
    <groupId>com.aol.simplereact</groupId>
    <artifactId>cyclops-react</artifactId>
    <version>2.0.0-MI1</version>
</dependency>

Documentation

Articles

Old simple-react landing page

License

cyclops-react is licensed under the Apache 2.0 license.

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