Monix: Version 2.0.0 Final Release

Monix is a library for composing asynchronous, event-based programs. Work on version 2.0 started since December last year, after version 1.0 was released.

Today marks the release of the 2.0.0 version. Here’s what happened since 1.0:

  1. the project went through a rename (from Monifu to Monix)
  2. the underlying protocol of Observable has been reviewed and changed quite significantly, making observable streams cancelable
  3. many of the Observable operators where refactored and improved
  4. the project was split into multiple sub-projects, such that users can pick and choose what they need
  5. the Task and Coeval types were introduced
  6. the project’s code coverage has been raised over 83%
  7. the project is in Typelevel’s Incubator, which for you it means that it plays nice with the other Typelevel projects
  8. it now integrates with Typelevel Cats and with Scalaz, which are THE standard libraries for doing functional programming and yes, Task, Coeval and Observable are provably Monads :-)
  9. we initiated a documentation website at Monix.io, with an initial batch of useful articles, though there’s still a lot of ground left to cover for observables

Today Monix 2.0.0 is being released for Scala 2.10.6, 2.11.8 and 2.12.0-M5, Scala.js 0.6.11, Cats 0.7.0 and Scalaz 7.2.5.

You can hit the documentation, or experiment in ScalaFiddle and see Monix in your browser, or take a look at monix-sample, a client/server communication sample with both sides handled by Monix (see it running).

See the published API Documentation.

The full list of issues follows. Note that this list represents a historical trail, but doesn’t necessarily represent the released 2.0.0, as sometimes work that happened in an earlier issue was changed again in a later issue.

  • Issue #60 - initiated the docs sub-project with tutorials type-checked as part of the test process
  • Issue #88 - add Monix’s own Task, an alternative to Future and the Scalaz Task
  • Issue #89 - initial integration with Cats
  • Issue #90 - remove functionality that isn’t relevant to the purpose of Monix and be supported
  • Issue #91 - project rename and reorganization (epic API breakage)
  • Issue #93 - renamed Observable.onSubscribe to Observable.unsafeSubscribeFn, because it shouldn’t be used directly, unless you really, really know what you’re doing
  • Issue #94 - fixed comments style to ScalaDoc
  • Issue #96 - removed Observable.create because it is unsafe
  • Issue #100 - enhanced the Scheduler interface
  • Issue #102 - brought back sun.misc.Unsafe (actually this was done in separate project, as part of issue #104)
  • Issue #104 - separated the Atomic implementations
  • Issue #106 - enabled code coverage reports
  • Issue #111 - improved test coverage
  • Issue #114 - initiated the benchmarks sub-project to track performance issues
  • Issue #115 - Cancelable.cancel now returns Unit and not Boolean
  • Issue #118 - Fix materialize, add dematerialize
  • Issue #119 - Introduced Pipe, renamed Channel in ConcurrentSubject, renamed SynchronousObserver in SyncObserver, renamed SynchronousSubscriber in SyncSubscriber
  • Issue #121 - Clarified the contract for synchronous pipelines, got rid of the hacks from internal, replacing them with macro-driven extensions for Future[Ack]
  • Issue #123 - Changed the protocol of Observable.subscribe, back-pressuring onComplete and onError is now optional and Observable.unsafeSubscribeFn needs to return a usable Cancelable instead of Unit (big internal change)
  • Issue #125 - Modified contract of AsyncScheduler, added a new ExecutorScheduler
  • Issue #88: the Task implementation has been redesigned from scratch
  • Issue #89: Cats integration has been tried and yielded very positive results, but is being delayed
  • Issue #96 and issue 99: add MulticastStrategy for safer building of multicast Observables
  • Issue #127: Introduce operators onErrorHandle and onErrorHandleWith
  • Issue #128: operators materialize, dematerialize and memoize for Task (and Coeval)
  • Issue #113: Introduce the bufferIntrospective operator
  • Issue #123: underlying protocol changes, did some fixes for the work that already happened for M1
  • Issue #131: renamed Ack.Cancel to Ack.Stop in order to differentiate it as a verb from Cancelable.cancel, because in version 2.0 they are two different actions (and it’s more semantically correct this way)
  • Issue #132: introduced the Observable.onCancelTriggerError operator
  • Issue #133: introduced the Observable.doOnDownstreamStop and doOnCancel (which is one reason for #131)
  • Issue #134: New operator Observable.switchIfEmpty
  • Issue #136: Clarify reactive streams, initiated monix.execution.rstreams for reusable subscription types and added the ReactivePublisher type-class for things that can be converted to org.reactivestreams.Publisher (both Observable and Task are instances)
  • Issue #140: Add type-class hierarchy, to be integrated with both Cats and Scalaz
  • Issue #141: reimplement Task from scratch, introduce Coeval, introduce Scheduler.executionModel
  • Issue #143 - on RefCountObservable cancel and stop should be idempotent
  • Issue #144 - fix Observable.zip
  • Issue #147 - Make BehaviorSubject and ReplaySubject remove subscribers that triggered Stop while connecting, thus freeing the memory sooner, otherwise the GC cannot free the subscriber because its reference is kept captive until the next Subject.onNext
  • Issue #89 - reintroducing a minimal Cats integration, along with tests based on cats-laws. We are splitting monix.type into its own sub-project and monix-cats depends on it. This ensures that the pick what you use approach also works with monix-cats, as people wanting just Task should not get Observable, yet Observable needs integration as well.
  • Issue #149 - documentation related fixes
    • Improved the description of Task
    • Task.unit is now a final val
    • Task.never now shares the reference instead of building a new instance every time
    • Exposing Task.unsafeStartNow and Task.unsafeStartAsync, as otherwise Task.unsafeCreate is useless. So we should expose all of them, or none at all.
    • FutureUtils.Extensions.dematerialize was named “materialize” (WTF!) and is renamed
    • Task should inherit just from Serializable and not from Product
  • Issue #150 - add a new Task.doOnFinish operator that executes once a task is finished.
  • Issue #151 - changing Future.sequence to be ordered in both execution and effects
  • Issue #152 - introduce Task.gather which behaves like the previous sequence and Task.gatherUnordered which doesn’t do ordering for results either.
  • Bug 153 - Task.sequence and Task.gather return a shared mutable.ListBuffer
  • Bug #153: already fixed in 2.0-RC5 for Task, but now also fixed for Coeval
  • Issue #155: Coeval enhancements and fixes
  • Issue #156: Adding Observable.doOnTerminate for executing a piece of logic when onComplete or onError happens, or when the subscriber stops the streaming with Stop
  • Issue #158: Observable.fromIterator takes now an optional onFinish callback for resource deallocation, because the Iterator interface doesn’t provide a close() that could be used
  • Issue #163: added Observable.fromInputStream, fromCharsReader and fromLinesReader for reading from java.io.InputStream, java.io.Reader and java.io.BufferedReader data sources
  • Issue #164: Add Observable.executeOn, as alternative to observeOn
  • Issue #165: Simplification of the Cats integration
  • Issue #157: Renaming Observable.doOnCancel to doOnSubscriptionCancel because its meaning has changed since Monifu 1.x and it will cause pain
  • Issue #160 (breaking change): Revamp the buffer operators on Observable
  • Issue #161 (breaking change): Revamp the ConcurrentSubject and Pipe constructors
  • Issue #171: Add Scheduler builder on the JVM that allows specifying just the ExecutionModel, falling back global otherwise
  • Issue #174: Scalaz integration (in addition to the Cats integration) for FP goddess
  • Issue #175: Reintroduce all of project Sincron into monix-execution, which means that now monix-execution exposes Atomic references. This project was split from Monix, but the decision didn’t make sense and the exposed functionality is super useful and in the spirit of monix-execution
  • Issue #176: now that we have Task, we introduce TaskApp, a safe App type that allows one to specify pure programs
  • Issue #170: Task.materializeAttempt doesn’t work for BindAsync, leading to onErrorHandleWith not working with errors triggered in flatMap on async tasks
  • Issue #184: introducing the Consumer type, a factory of subscribers that makes it easier to specify reusable and composable consumers and for example, it makes it possible, out of the box, to load-balance the workload between multiple subscribers in parallel; see the description
  • Issue #186 (related to issue #168): adds the Observable.interleave2 operator, similar with the one in FS2 (former scalaz-streams)
  • Issue #180: the Observer.feed function now has an overload that does not take a cancelable, because it’s awkward coming up with one if it isn’t needed; there’s also a onNextAll extension for both Observer and Subscriber which can push a whole collection of events
  • Issue #187: integrates the MonadCombine type-class from Cats, being similar to the Scalaz MonadPlus, as somehow this was missed in the initial integration
  • Issue #177 reviews exposed traits and abstract classes, making sure they inherit from Serializable
  • Issue #85: small change,
    clarifies the ScalaDoc on the RefCountCancelable type
  • Issue #162: implements the Observable.takeUntil(trigger: Observable[Any]) operator, an operator that takes from the source until another observable triggers an event
  • Issue #189: for Observable operators that return a single item (e.g. sumF, foldLeftF, etc.) adds variants that do the same thing, but return Task results instead, so now we have foldLeftL, sumL, etc. that return tasks
  • Issue #190: changes many observable operators, that were taking by-name parameters or initial state parameters (e.g. headOrElseF, foldLeftF, etc), to take Coeval params instead, in order to have fine control over the evaluation model
  • Issue #191: introduces by default an implicit conversion from Any to Coeval.Now, to make it easier to use Coeval as function parameters - the default will thus simply be strict evaluation, strictness being usually the default in Scala
  • Issue #181: the default operators on CancelableFuture are triggering StackOverflow exceptions
  • Issue #196: Add the Consumer.create builder
  • Issue #166: Generalize Task.sequence, Task.gather and Task.gatherUnordered for arbitrary collections
  • Issue #193: Task Applicative instance doesn’t run the tasks in parallel
  • Issue #194: Task.mapBoth is not stack-safe
  • Issue #200: Add an executeNow extension method for Scheduler, taking a by-name callback, as initializing Runnable instances is too annoying
  • Issue #201: Fixes and optimizes Task.gatherUnordered - as an edge-case, it wasn’t stack safe and it has been optimized to be more efficient
  • Issue #202: Added asyncOnSuccess and asyncOnError as extension methods for Callback and made Task.create safe by forcing an asynchronous boundary when calling the callback (onSuccess/onError); also optimizes Task.chooseFirstOfList and TestScheduler
  • Issue #203: Changed the onOverflow function signature for OverflowStrategy types supporting it - it can now return an Option and if it returns None, then we don’t signal any messages downstream, thus making it easier to just log that overflow happened without extra tricks
  • Issue #208: Uniquely name threads generated from ThreadFactory
  • Issue #210: Refactorings for performance and coherence reasons
  • Issue #207: Task flatMap loop isn’t cancelable
  • Issue #210: Fixed CompositeCancelable.remove, a bug introduced in the last release (RC10)
  • Issue #212: Upgraded Cats to version 0.7.0
  • Issue #214: optimize Task, refactorings, some deprecations
  • Issue #211: CompositeCancelable.remove wasn’t working after the changes in RC10, fixed it in RC11 and now added some more tests
  • Issue #213: Fixes Task / Coeval memoize operation
  • Issue #215: the instance created by Task.gatherUnordered keeps state and has problems running (with runAsync) a second time
  • Issue #216: Change type-class design in monix.types to an encoding inspired by the Scato and Scalaz 8, cleaning up the available types; also enable 2.12.0-M5 support, although releases are not automatic, because Cats doesn’t yet support Scala 2.12

Enjoy!